diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000000..e7a976a7be4 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,18 @@ +* @element-hq/element-web-reviewers +/.github/workflows/** @element-hq/element-web-team +/package.json @element-hq/element-web-team +/yarn.lock @element-hq/element-web-team + +/src/SecurityManager.ts @element-hq/element-crypto-web-reviewers +/test/SecurityManager-test.ts @element-hq/element-crypto-web-reviewers +/src/async-components/views/dialogs/security/ @element-hq/element-crypto-web-reviewers +/src/components/views/dialogs/security/ @element-hq/element-crypto-web-reviewers +/test/components/views/dialogs/security/ @element-hq/element-crypto-web-reviewers +/src/stores/SetupEncryptionStore.ts @element-hq/element-crypto-web-reviewers +/test/stores/SetupEncryptionStore-test.ts @element-hq/element-crypto-web-reviewers + +# Ignore translations as those will be updated by GHA for Localazy download +/src/i18n/strings +# Ignore the synapse plugin as this is updated by GHA for docker image updating +/playwright/plugins/homeserver/synapse/index.ts + diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000000..afc29f01425 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,2 @@ +patreon: matrixdotorg +liberapay: matrixdotorg diff --git a/.github/ISSUE_TEMPLATE/bug-desktop.yml b/.github/ISSUE_TEMPLATE/bug-desktop.yml new file mode 100644 index 00000000000..529c0a0ebcf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-desktop.yml @@ -0,0 +1,76 @@ +name: Bug report for the Element desktop app (not in a browser) +description: File a bug report if you are using the desktop Element application. +labels: [T-Defect] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + + Please report security issues by email to security@matrix.org + - type: textarea + id: reproduction-steps + attributes: + label: Steps to reproduce + description: Please attach screenshots, videos or logs if you can. + placeholder: Tell us what you see! + value: | + 1. Where are you starting? What can you see? + 2. What do you click? + 3. More steps… + validations: + required: true + - type: textarea + id: result + attributes: + label: Outcome + placeholder: Tell us what went wrong + value: | + #### What did you expect? + + #### What happened instead? + validations: + required: true + - type: input + id: os + attributes: + label: Operating system + placeholder: Windows, macOS, Ubuntu, Arch Linux… + validations: + required: false + - type: input + id: version + attributes: + label: Application version + description: You can find the version information in Settings -> Help & About. + placeholder: e.g. Element version 1.7.34, olm version 3.2.3 + validations: + required: false + - type: input + id: source + attributes: + label: How did you install the app? + description: Where did you install the app from? Please give a link or a description. + placeholder: e.g. From https://element.io/get-started + validations: + required: false + - type: input + id: homeserver + attributes: + label: Homeserver + description: | + Which server is your account registered on? If it is a local or non-public homeserver, please tell us what is the homeserver implementation (ex: Synapse/Dendrite/etc.) and the version. + placeholder: e.g. matrix.org or Synapse 1.50.0rc1 + validations: + required: false + - type: dropdown + id: rageshake + attributes: + label: Will you send logs? + description: | + Did you know that you can send a /rageshake command from your application to submit logs for this issue? Trigger the defect, then type `/rageshake` into the message input area followed by a description of the problem and send the command. You will be able to add a link to this defect report and submit anonymous logs to the developers. + options: + - "Yes" + - "No" + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/bug-web.yml b/.github/ISSUE_TEMPLATE/bug-web.yml new file mode 100644 index 00000000000..24ab78a153d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-web.yml @@ -0,0 +1,84 @@ +name: Bug report for Element Web (in browser) +description: File a bug report if you are using Element in a web browser like Firefox, Chrome, Edge, and so on. +labels: [T-Defect] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! + + Please report security issues by email to security@matrix.org + - type: textarea + id: reproduction-steps + attributes: + label: Steps to reproduce + description: Please attach screenshots, videos or logs if you can. + placeholder: Tell us what you see! + value: | + 1. Where are you starting? What can you see? + 2. What do you click? + 3. More steps… + validations: + required: true + - type: textarea + id: result + attributes: + label: Outcome + placeholder: Tell us what went wrong + value: | + #### What did you expect? + + #### What happened instead? + validations: + required: true + - type: input + id: os + attributes: + label: Operating system + placeholder: Windows, macOS, Ubuntu, Arch Linux… + validations: + required: false + - type: input + id: browser + attributes: + label: Browser information + description: Which browser are you using? Which version? + placeholder: e.g. Chromium Version 92.0.4515.131 + validations: + required: false + - type: input + id: webapp-url + attributes: + label: URL for webapp + description: Which URL are you using to access the webapp? If a private server, tell us what version of Element Web you are using. + placeholder: e.g. develop.element.io, app.element.io + validations: + required: false + - type: input + id: version + attributes: + label: Application version + description: You can find the version information in Settings -> Help & About. + placeholder: e.g. Element version 1.7.34, olm version 3.2.3 + validations: + required: false + - type: input + id: homeserver + attributes: + label: Homeserver + description: | + Which server is your account registered on? If it is a local or non-public homeserver, please tell us what is the homeserver implementation (ex: Synapse/Dendrite/etc.) and the version. + placeholder: e.g. matrix.org or Synapse 1.50.0rc1 + validations: + required: false + - type: dropdown + id: rageshake + attributes: + label: Will you send logs? + description: | + Did you know that you can send a /rageshake command from the web application to submit logs for this issue? Trigger the defect, then type `/rageshake` into the message input area followed by a description of the problem and send the command. You will be able to add a link to this defect report and submit anonymous logs to the developers. + options: + - "Yes" + - "No" + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 00000000000..b34e4493684 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Questions & support + url: https://matrix.to/#/#element-web:matrix.org + about: Please ask and answer questions here. diff --git a/.github/ISSUE_TEMPLATE/enhancement.yml b/.github/ISSUE_TEMPLATE/enhancement.yml new file mode 100644 index 00000000000..7dd384e78ff --- /dev/null +++ b/.github/ISSUE_TEMPLATE/enhancement.yml @@ -0,0 +1,36 @@ +name: Enhancement request +description: Do you have a suggestion or feature request? +labels: [T-Enhancement] +body: + - type: markdown + attributes: + value: | + Thank you for taking the time to propose an enhancement to an existing feature. If you would like to propose a new feature or a major cross-platform change, please [start a discussion here](https://github.com/element-hq/element-meta/discussions/new?category=ideas). + - type: textarea + id: usecase + attributes: + label: Your use case + description: What would you like to be able to do? Please feel welcome to include screenshots or mock ups. + placeholder: Tell us what you would like to do! + value: | + #### What would you like to do? + + #### Why would you like to do it? + + #### How would you like to achieve it? + validations: + required: true + - type: textarea + id: alternative + attributes: + label: Have you considered any alternatives? + placeholder: A clear and concise description of any alternative solutions or features you've considered. + validations: + required: false + - type: textarea + id: additional-context + attributes: + label: Additional context + placeholder: Is there anything else you'd like to add? + validations: + required: false diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 00000000000..16036541f88 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,8 @@ + + +## Checklist + +- [ ] Tests written for new code (and old code if feasible). +- [ ] New or updated `public`/`exported` symbols have accurate [TSDoc](https://tsdoc.org/) documentation. +- [ ] Linter and other CI checks pass. +- [ ] I have licensed the changes to Element by completing the [Contributor License Agreement (CLA)](https://cla-assistant.io/element-hq/element-web) diff --git a/.github/actions/download-verify-element-tarball/action.yml b/.github/actions/download-verify-element-tarball/action.yml new file mode 100644 index 00000000000..e61b96596bf --- /dev/null +++ b/.github/actions/download-verify-element-tarball/action.yml @@ -0,0 +1,39 @@ +name: Upload release assets +description: Uploads assets to an existing release and optionally signs them +inputs: + tag: + description: GitHub release tag to fetch assets from. + required: true + out-file-path: + description: Path to where the webapp should be extracted to. + required: true +runs: + using: composite + steps: + - name: Download release tarball + id: current_download + uses: robinraju/release-downloader@a96f54c1b5f5e09e47d9504526e96febd949d4c2 # v1 + with: + tag: ${{ inputs.tag }} + fileName: element-*.tar.gz* + out-file-path: ${{ runner.temp }}/download-verify-element-tarball + + - name: Verify tarball + shell: bash + run: gpg --verify element-*.tar.gz.asc element-*.tar.gz + working-directory: ${{ runner.temp }}/download-verify-element-tarball + + - name: Extract tarball + shell: bash + run: | + mkdir webapp + tar xvzf element-*.tar.gz -C webapp --strip-components=1 + working-directory: ${{ runner.temp }}/download-verify-element-tarball + + - name: Move webapp to out-file-path + shell: bash + run: mv ${{ runner.temp }}/download-verify-element-tarball/webapp ${{ inputs.out-file-path }} + + - name: Clean up temp directory + shell: bash + run: rm -R ${{ runner.temp }}/download-verify-element-tarball diff --git a/.github/cfp_headers b/.github/cfp_headers index 482c9ead0dd..497a5ff58d9 100644 --- a/.github/cfp_headers +++ b/.github/cfp_headers @@ -5,7 +5,6 @@ X-Frame-Options: SAMEORIGIN Content-Security-Policy: frame-ancestors 'self' Strict-Transport-Security: max-age=31536000; includeSubDomains; preload - permissions-policy: accelerometer=(), gyroscope=(), magnetometer=(), usb=(), interest-cohort=() /version Content-Type: text/plain diff --git a/.github/labels.yml b/.github/labels.yml new file mode 100644 index 00000000000..80c5408c1e3 --- /dev/null +++ b/.github/labels.yml @@ -0,0 +1,269 @@ +- name: "A-Aliases" + color: "bfd4f2" +- name: "A-Authentication" + color: "bfd4f2" +- name: "A-Autocomplete" + color: "bfd4f2" +- name: "A-Breadcrumbs" + color: "bfd4f2" +- name: "A-Bridge" + color: "bfd4f2" +- name: "A-Broadcast" + description: "Broadcast-style voice messages" + color: "bfd4f2" +- name: "A-Create-Room" + description: "Create room flow, user suggestions, etc." + color: "bfd4f2" +- name: "A-DevTools" + description: "/devtools, show hidden events, etc." + color: "bfd4f2" +- name: "A-Dialogs" + color: "bfd4f2" +- name: "A-Disambiguation" + color: "bfd4f2" +- name: "A-DM-Start" + description: "Creating a DM with another user" + color: "bfd4f2" +- name: "A-E2EE-Dehydration" + color: "8CC59A" +- name: "A-Electron" + color: "bfd4f2" +- name: "A-Element-Call" + description: "Group calls via Element Call" + color: "bfd4f2" +- name: "A-Element-R" + description: "Issues affecting the port of Element's crypto layer to Rust" + color: "bfd4f2" +- name: "A-ELS" + description: "Event List Summary (and Membership ELS, MELS)" + color: "bfd4f2" +- name: "A-Emotes" + color: "bfd4f2" +- name: "A-EMS" + description: "Issues related to EMS" + color: "bfd4f2" +- name: "A-Error-Message" + color: "bfd4f2" +- name: "A-Federation" + color: "bfd4f2" +- name: "A-Feedback-Reporting" + description: "Reporting process for bugs, debug logs (rageshakes), suggestions" + color: "bfd4f2" +- name: "A-File-Download" + color: "bfd4f2" +- name: "A-File-Panel" + color: "bfd4f2" +- name: "A-Identity-Server" + color: "bfd4f2" +- name: "A-Indexing" + description: "Indexing messages via Seshat" + color: "bfd4f2" +- name: "A-IRC-Layout" + color: "bfd4f2" +- name: "A-Jump-To-Date" + description: "Jump to date headers or slash command" + color: "bfd4f2" +- name: "A-Lazy-Loading" + color: "bfd4f2" +- name: "A-Light-Box" + description: "UI when viewing an image" + color: "bfd4f2" +- name: "A-Location-Sharing" + color: "bfd4f2" +- name: "A-Logout" + description: "Logout, sign out, etc." + color: "bfd4f2" +- name: "A-Maths" + description: "Render LaTeX maths in messages" + color: "bfd4f2" +- name: "A-Memory" + description: "Memory leaks, leak hunting tools" + color: "bfd4f2" +- name: "A-Message-Forwarding" + color: "bfd4f2" +- name: "A-Message-Pinning" + color: "bfd4f2" +- name: "A-Message-Previews" + color: "bfd4f2" +- name: "A-Message-Starring" + description: "Saving favourite messages for later" + color: "bfd4f2" +- name: "A-Modules" + description: "Module system related" + color: "bfd4f2" +- name: "A-New-Search-Experience" + description: "The new search dialog available in Labs" + color: "bfd4f2" +- name: "A-Packaging" + description: "Packaging, signing, releasing" + color: "bfd4f2" +- name: "A-Peeking" + color: "bfd4f2" +- name: "A-Picture-in-Picture" + color: "bfd4f2" +- name: "A-Power-Levels" + description: "The permissions that users have in rooms and spaces" + color: "bfd4f2" +- name: "A-Replies" + description: "reply" + color: "bfd4f2" +- name: "A-Session-Mgmt" + description: "Session / device names, management UI, etc." + color: "bfd4f2" +- name: "A-Share" + color: "bfd4f2" +- name: "A-Shortcuts" + description: "Keyboard shortcuts" + color: "bfd4f2" +- name: "A-Sliding-Sync" + description: "Also known as Sync v3 - https://github.com/matrix-org/sliding-sync" + color: "bfd4f2" +- name: "A-Soft-Logout" + description: "https://github.com/element-hq/element-web/issues/10224" + color: "bfd4f2" +- name: "A-Spaces-Settings" + color: "bfd4f2" +- name: "A-SSO" + color: "bfd4f2" +- name: "A-Status-Bar" + description: "Unsent messages warning and 'Connectivity to the server has been lost'" + color: "bfd4f2" +- name: "A-Storage" + description: "Storage layer of the app, including IndexedDB, local storage, etc." + color: "bfd4f2" +- name: "A-Technical-Debt" + color: "bfd4f2" +- name: "A-Testing" + description: "Testing, code coverage, etc." + color: "bfd4f2" +- name: "A-Themes-Custom" + description: "Custom theme variables or support" + color: "bfd4f2" +- name: "A-Themes-Official" + description: "Official themes (light, dark)" + color: "bfd4f2" +- name: "A-Theming" + color: "bfd4f2" +- name: "A-Timeline-Jumpy-Scroll" + description: "Stable timeline dream ✨" + color: "bfd4f2" +- name: "A-Timesheet-1" + description: "Log any time spent on this into the A-Timesheet-1 project" + color: "5319E7" +- name: "A-Toast" + color: "bfd4f2" +- name: "A-Tooltips" + description: "Anything related to tooltips" + color: "bfd4f2" +- name: "A-UI-Customisation" + description: "UIFeatures etc. for customising entire parts of the UI" + color: "bfd4f2" +- name: "A-URL-Previews" + color: "bfd4f2" +- name: "A-User-Menu" + description: "The top left main menu with the user's name and avatar" + color: "bfd4f2" +- name: "A-User-Search" + description: "The start DM or invite to room dialogs (things dealing with `/user_directory/search`)" + color: "bfd4f2" +- name: "A-Video-Rooms" + description: "Persistent group calls" + color: "bfd4f2" +- name: "A-Voice-Messages" + color: "bfd4f2" +- name: "A-Welcome-Page" + color: "bfd4f2" +- name: "backport staging" + description: "Label to automatically backport PR to staging branch" + color: "B60205" +- name: "Dependencies" + description: "Pull requests that update a dependency file" + color: "0366d6" +- name: "Hacktoberfest" + description: "Issues which are suitable for Hacktoberfest PRs: https://hacktoberfest.digitalocean.com/" + color: "ff7518" +- name: "P4" + description: "[OBSOLETE LABEL] Interesting — Not yet scheduled, will accept patches" + color: "d1e5f0" +- name: "spam" + color: "B60205" +- name: "Sponsored" + color: "ffc8f4" +- name: "T-Deprecation" + description: "A pull request that makes something deprecated" + color: "98e6ae" +- name: "T-Other" + description: "Questions, user support, anything else" + color: "98e6ae" +- name: "Team: App" + color: "FFA500" +- name: "X-Blocked" + color: "ff7979" +- name: "X-Cannot-Reproduce" + color: "ff7979" +- name: "X-Command" + description: "Created using the !github command" + color: "ff7979" +- name: "X-Community-Supported-Platform" + description: "This issue occurs in a platform not directly supported by us, but by a community project elsewhere" + color: "ff7979" +- name: "X-Upcoming-Release-Blocker" + description: "This does not affect the current release cycle but will affect the next one" + color: "e99695" +- name: "Z-Actions" + color: "ededed" +- name: "Z-Cache-Confusion" + description: "Related to internal cache (clearing helps / causes the issue)" + color: "ededed" +- name: "Z-Community-PR" + description: "Issue is solved by a community member's PR" + color: "ededed" +- name: "Z-Element-R-Blocker" + description: "A blocker for enabling Element R by default" + color: "ededed" +- name: "Z-Experimental" + color: "ededed" +- name: "Z-Fixed by Element Call" + description: "Issues which can be closed when we move to Element Call" + color: "ededed" +- name: "Z-Fixed-By-OIDC" + description: "Issues which can be closed when we move to OIDC" + color: "ededed" +- name: "Z-Flaky-Test" + description: "A test is raising false alarms" + color: "ededed" +- name: "Z-Flaky-Jest-Test" + description: "A Jest test is raising false alarms" + color: "ededed" +- name: "Z-FOSDEM" + description: "Issues in chat.fosdem.org" + color: "ededed" +- name: "Z-Gitter" + description: "Issues relating to or coming out of the Gitter migration, feature parity, etc" + color: "ededed" +- name: "Z-Legacy-Crypto" + description: "Issues affecting the legacy crypto stack" + color: "EEEEEE" +- name: "Z-Maximised-Widgets" + color: "ededed" +- name: "Z-Papercuts" + description: "Visible. Impactful. Predictable to action." + color: "ededed" +- name: "Z-Power-Users" + color: "ededed" +- name: "Z-Rageshake" + description: "Has attached rageshake (not for log submission process)" + color: "ededed" +- name: "Z-RICE" + color: "ededed" +- name: "Z-Soft-Crash" + description: "React soft crash caught by an error boundary" + color: "ededed" +- name: "Z-Spec-Compliance" + description: "An area where Element doesn't correctly implement the spec" + color: "ededed" +- name: "Z-t3chguy" + color: "ededed" +- name: "Z-Flaky-Test-Disabled" + description: "The flaking test has been disabled" + color: "ededed" diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 00000000000..5045f2bfc9e --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,3 @@ +_extends: matrix-org/matrix-js-sdk +version-resolver: + default: patch diff --git a/.github/renovate.json b/.github/renovate.json new file mode 100644 index 00000000000..76320426d9e --- /dev/null +++ b/.github/renovate.json @@ -0,0 +1,4 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": ["github>matrix-org/renovate-config-element-web"] +} diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml new file mode 100644 index 00000000000..5a11ad5bbd5 --- /dev/null +++ b/.github/workflows/backport.yml @@ -0,0 +1,32 @@ +name: Backport +on: + pull_request_target: + types: + - closed + - labeled + branches: + - develop + +permissions: {} # We use ELEMENT_BOT_TOKEN instead + +jobs: + backport: + name: Backport + runs-on: ubuntu-24.04 + # Only react to merged PRs for security reasons. + # See https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target. + if: > + github.event.pull_request.merged + && ( + github.event.action == 'closed' + || ( + github.event.action == 'labeled' + && contains(github.event.label.name, 'backport') + ) + ) + steps: + - uses: tibdex/backport@9565281eda0731b1d20c4025c43339fb0a23812e # v2 + with: + labels_template: "<%= JSON.stringify([...labels, 'X-Release-Blocker']) %>" + # We can't use GITHUB_TOKEN here or CI won't run on the new PR + github_token: ${{ secrets.ELEMENT_BOT_TOKEN }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 19afbe5c32d..381755b6067 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,7 +2,7 @@ name: Build on: pull_request: {} push: - branches: [release, master] + branches: [develop, master] merge_group: types: [checks_requested] # develop pushes and repository_dispatch handled in build_develop.yaml @@ -20,8 +20,8 @@ jobs: matrix: image: - ubuntu-24.04 - # - windows-2022 - # - macos-14 + - windows-2022 + - macos-14 isDevelop: - ${{ github.event_name == 'push' && github.ref_name == 'develop' }} # Skip the ubuntu-24.04 build for the develop branch as the dedicated CD build_develop workflow handles that @@ -46,107 +46,5 @@ jobs: - name: Install Dependencies run: "./scripts/layered.sh" - # - name: Build - # run: "yarn build" - - # Build step from develop workflow - - name: Build and Package - run: "./scripts/ci_package.sh" - - - run: mv dist/elecord-*.tar.gz dist/elecord.tar.gz - - - name: Upload Artifact - uses: actions/upload-artifact@v4 - with: - name: webapp - path: dist/elecord.tar.gz - - deploy: - needs: build - name: Deploy webapp - runs-on: ubuntu-24.04 - permissions: - pull-requests: write - steps: - # Download and extract the build folder - - name: Download Artifact - uses: actions/download-artifact@v4 - with: - name: webapp - path: . - - - name: Extract tarball - run: tar -xvzf elecord.tar.gz - - - name: Move to dist - run: mv elecord-*/ dist - - # Set the Cloudflare pages branch name - # - PR to master : test - # - Push to master : dev - # - PR to release : preview - # - Push to release : release (Production environment) - - name: Set Pages branch - run: | - if [[ "${{ github.event_name }}" == "pull_request" ]]; then - if [[ "${{ github.event.pull_request.base.ref }}" == "master" ]]; then - echo "cf_branch=test" >> $GITHUB_ENV - elif [[ "${{ github.event.pull_request.base.ref }}" == "release" ]]; then - echo "cf_branch=preview" >> $GITHUB_ENV - fi - elif [[ "${{ github.event_name }}" == "push" ]]; then - if [[ "${{ github.ref_name }}" == "master" ]]; then - echo "cf_branch=dev" >> $GITHUB_ENV - elif [[ "${{ github.ref_name }}" == "release" ]]; then - echo "cf_branch=release" >> $GITHUB_ENV - fi - fi - - # Deploy to Cloudflare Pages (using wrangler) - - name: Deploy to Cloudflare Pages - id: cf - uses: cloudflare/wrangler-action@v3 - with: - apiToken: ${{ secrets.CLOUDFLARE_PAGES_API_TOKEN }} - accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - command: pages deploy dist --project-name=elecord-web --branch=${{ env.cf_branch }} - - # Update PR status comment with deployment URL - - name: Update status comment (Failure) - if: ${{ github.event_name == 'pull_request' && failure() }} - uses: thollander/actions-comment-pull-request@v3 - with: - message: | - ## Cloudflare Pages deployment - - | **Latest commit** | ${{ github.event.pull_request.head.sha || github.sha }} | - |-------------------|:-:| - | **Status** | ❌ Failure. Check workflow logs for details | - | **Preview URL** | Not available | - pr-number: ${{ github.event.pull_request.number }} - comment-tag: CFPages-deployment - reactions: -1 - mode: recreate - - # When deploying to the preview branch, add the preview URL - - name: Add preview URL - run: | - if [[ "${{ env.cf_branch }}" == "preview" ]]; then - echo -e "cf_preview=https://preview.elecord.app\n" >> $GITHUB_ENV - fi - - - name: Update status comment (Success) - if: ${{ github.event_name == 'pull_request' && success() }} - uses: thollander/actions-comment-pull-request@v3 - with: - message: | - ## Cloudflare Pages deployment - - | **Latest commit** | ${{ github.event.pull_request.head.sha || github.sha }} | - |-------------------|:-:| - | **Status** | ✅ Deployed! | - | **URL** | ${{ env.cf_preview }}${{ steps.cf.outputs.deployment-url != '' && steps.cf.outputs.deployment-url || 'Not available' }} | - pr-number: ${{ github.event.pull_request.number }} - comment-tag: CFPages-deployment - reactions: rocket - mode: recreate \ No newline at end of file + - name: Build + run: "yarn build" diff --git a/.github/workflows/build_debian.yaml b/.github/workflows/build_debian.yaml new file mode 100644 index 00000000000..f46678512a7 --- /dev/null +++ b/.github/workflows/build_debian.yaml @@ -0,0 +1,79 @@ +name: Build Debian package +on: + release: + types: [published] +concurrency: ${{ github.workflow }} +permissions: {} # We use ELEMENT_BOT_TOKEN instead +jobs: + build: + name: Build package + environment: packages.element.io + runs-on: ubuntu-24.04 + env: + R2_INCOMING_BUCKET: ${{ vars.R2_INCOMING_BUCKET }} + R2_URL: ${{ vars.CF_R2_S3_API }} + VERSION: ${{ github.ref_name }} + steps: + - uses: actions/checkout@v4 + + - name: Download package + run: | + wget "https://github.com/element-hq/element-web/releases/download/$VERSION/element-$VERSION.tar.gz" + wget "https://github.com/element-hq/element-web/releases/download/$VERSION/element-$VERSION.tar.gz.asc" + + - name: Check GPG signature + run: | + wget "https://packages.element.io/element-release-key.gpg" + gpg --import element-release-key.gpg + gpg --fingerprint "$FINGERPRINT" + gpg --verify "element-$VERSION.tar.gz.asc" "element-$VERSION.tar.gz" + env: + FINGERPRINT: ${{ vars.GPG_FINGERPRINT }} + + - name: Prepare + run: | + mkdir -p debian/tmp/DEBIAN + find debian -maxdepth 1 -type f -exec cp "{}" debian/tmp/DEBIAN/ \; + mkdir -p debian/tmp/usr/share/element-web/ debian/tmp/etc/element-web/ + + tar -xf "element-$VERSION.tar.gz" -C debian/tmp/usr/share/element-web --strip-components=1 --no-same-owner --no-same-permissions + mv debian/tmp/usr/share/element-web/config.sample.json debian/tmp/etc/element-web/config.json + ln -s /etc/element-web/config.json debian/tmp/usr/share/element-web/config.json + + - name: Write changelog + run: | + VERSION=$(cat package.json | jq -r .version) + TIME=$(date -d "$PUBLISHED_AT" -R) + { + echo "element-web ($VERSION) default; urgency=medium" + echo "$BODY" | sed 's/^##/\n */g;s/^\*/ */g' | perl -pe 's/\[.+?]\((.+?)\)/\1/g' + echo "" + echo " -- $ACTOR $TIME" + } > debian/tmp/DEBIAN/changelog + env: + ACTOR: ${{ github.actor }} + VERSION: ${{ github.event.release.tag_name }} + BODY: ${{ github.event.release.body }} + PUBLISHED_AT: ${{ github.event.release.published_at }} + + - name: Build deb package + run: | + VERSION=$(cat package.json | jq -r .version) + dpkg-gencontrol -v"$VERSION" -ldebian/tmp/DEBIAN/changelog + dpkg-deb -Zxz --root-owner-group --build debian/tmp element-web.deb + + - uses: actions/upload-artifact@v4 + with: + name: element-web.deb + path: element-web.deb + retention-days: 14 + + - name: Publish to packages.element.io + if: github.event.release.prerelease == false + uses: element-hq/packages.element.io@master + with: + file: element-web.deb + github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} + bucket-api: ${{ vars.CF_R2_S3_API }} + bucket-key-id: ${{ secrets.CF_R2_ACCESS_KEY_ID }} + bucket-access-key: ${{ secrets.CF_R2_TOKEN }} diff --git a/.github/workflows/build_develop.yml b/.github/workflows/build_develop.yml new file mode 100644 index 00000000000..8bbcfe726f5 --- /dev/null +++ b/.github/workflows/build_develop.yml @@ -0,0 +1,131 @@ +# Separate to the main build workflow for access to develop +# environment secrets, largely similar to build.yaml. +name: Build and Deploy develop +on: + push: + branches: [develop] + repository_dispatch: + types: [element-web-notify] +concurrency: + group: ${{ github.repository_owner }}-${{ github.workflow }}-${{ github.ref_name }} + cancel-in-progress: true +permissions: {} +jobs: + build: + name: "Build & Deploy develop.element.io" + # Only respect triggers from our develop branch, ignore that of forks + if: github.repository == 'element-hq/element-web' + runs-on: ubuntu-24.04 + environment: develop + permissions: + checks: read + pages: write + deployments: write + env: + R2_BUCKET: "element-web-develop" + R2_URL: ${{ vars.CF_R2_S3_API }} + R2_PUBLIC_URL: "https://element-web-develop.element.io" + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + cache: "yarn" + node-version: "lts/*" + + - name: Install Dependencies + run: "./scripts/layered.sh" + + - name: Build, Package & Upload sourcemaps + run: "./scripts/ci_package.sh" + env: + SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} + SENTRY_DSN: ${{ secrets.SENTRY_DSN }} + SENTRY_URL: ${{ secrets.SENTRY_URL }} + SENTRY_ORG: element + SENTRY_PROJECT: riot-web + # We only deploy the latest bundles to Cloudflare Pages and use _redirects to fallback to R2 for + # older ones. This redirect means that 'self' is insufficient in the CSP, + # and we have to add the R2 URL. + # Once Cloudflare redirects support proxying mode we will be able to ditch this. + # See Proxying in support table at https://developers.cloudflare.com/pages/platform/redirects + CSP_EXTRA_SOURCE: ${{ env.R2_PUBLIC_URL }} + + - run: mv dist/element-*.tar.gz dist/develop.tar.gz + + - uses: actions/upload-artifact@v4 + with: + name: webapp + path: dist/develop.tar.gz + retention-days: 1 + + - name: Extract webapp + run: | + mkdir _deploy + tar xf dist/develop.tar.gz -C _deploy --strip-components=1 + + - name: Copy config + run: cp element.io/develop/config.json _deploy/config.json + + - name: Populate 404.html + run: echo "404 Not Found" > _deploy/404.html + + - name: Populate _headers + run: cp .github/cfp_headers _deploy/_headers + + # Redirect requests for the develop tarball and the historical bundles to R2 + # We find the latest 100 bundle.css files and add their bundles to the redirects file + # S3 has no sane way to get the age of a directory as they don't really exist + - name: Populate _redirects + run: | + { + echo "/develop.tar.gz $R2_PUBLIC_URL/develop.tar.gz 301" + aws s3api --region auto --endpoint-url $R2_URL list-objects-v2 --bucket $R2_BUCKET \ + --query "sort_by(Contents[?ends_with(Key, '/bundle.css')], &LastModified)[-100:].Key" \ + --prefix "bundles/" | jq -r '.[]' | grep -oE '[^\"].*\/\s*' | while read -r path ; do + echo "/${path}* $R2_PUBLIC_URL/${path}:splat 301" + done + } | tee _deploy/_redirects + env: + AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_TOKEN }} + + # We may be trying to deploy the same webapp bundles again, we need to ensure that the live bundles + # are not present in the _redirects file and instead accessed directly from Cloudflare Pages. + - name: Trim _redirects + working-directory: _deploy + run: | + find bundles -type d -mindepth 1 -maxdepth 1 -exec sed -i "\:{}:d" _redirects \; + + - name: Wait for other steps to succeed + uses: t3chguy/wait-on-check-action@18541021811b56544d90e0f073401c2b99e249d6 # fork + with: + ref: ${{ github.sha }} + running-workflow-name: "Build & Deploy develop.element.io" + repo-token: ${{ secrets.GITHUB_TOKEN }} + wait-interval: 10 + check-regexp: ^((?!SonarCloud|SonarQube|issue|board|label|Release|prepare|GitHub Pages).)*$ + + # We keep the latest develop.tar.gz on R2 instead of relying on the github artifact uploaded earlier + # as the expires after 24h and requires auth to download. + # Element Desktop's fetch script uses this tarball to fetch latest develop to build Nightlies. + - name: Deploy to R2 + run: | + aws s3 cp dist/develop.tar.gz s3://$R2_BUCKET/develop.tar.gz --endpoint-url $R2_URL --region=auto + aws s3 cp _deploy/ s3://$R2_BUCKET/ --recursive --endpoint-url $R2_URL --region=auto + env: + AWS_ACCESS_KEY_ID: ${{ secrets.CF_R2_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.CF_R2_TOKEN }} + + - name: Deploy to Cloudflare Pages + id: cfp + uses: cloudflare/pages-action@f0a1cd58cd66095dee69bfa18fa5efd1dde93bca # v1 + with: + apiToken: ${{ secrets.CF_PAGES_TOKEN }} + accountId: ${{ secrets.CF_PAGES_ACCOUNT_ID }} + projectName: element-web-develop + directory: _deploy + gitHubToken: ${{ secrets.GITHUB_TOKEN }} + + - run: | + echo "Deployed to ${{ steps.cfp.outputs.url }}" >> $GITHUB_STEP_SUMMARY diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml new file mode 100644 index 00000000000..ac6249d654a --- /dev/null +++ b/.github/workflows/deploy.yml @@ -0,0 +1,91 @@ +# Manual deploy workflow for deploying to app.element.io & staging.element.io +# Runs automatically for staging.element.io when an RC or Release is published +# Note: Does *NOT* run automatically for app.element.io so that it gets tested on staging.element.io beforehand +name: Deploy release +run-name: Deploy ${{ github.ref_name }} to ${{ inputs.site || 'staging.element.io' }} +on: + release: + types: [published] + workflow_dispatch: + inputs: + site: + description: Which site to deploy to + required: true + default: staging.element.io + type: choice + options: + - staging.element.io + - app.element.io +concurrency: ${{ inputs.site || 'staging.element.io' }} +permissions: {} +jobs: + deploy: + name: "Deploy to Cloudflare Pages" + runs-on: ubuntu-24.04 + environment: ${{ inputs.site || 'staging.element.io' }} + permissions: + checks: read + deployments: write + env: + SITE: ${{ inputs.site || 'staging.element.io' }} + steps: + - uses: actions/checkout@v4 + + - name: Load GPG key + run: | + curl https://packages.element.io/element-release-key.gpg | gpg --import + gpg -k "$GPG_FINGERPRINT" + env: + GPG_FINGERPRINT: ${{ vars.GPG_FINGERPRINT }} + + - name: Check current version on deployment + id: current_version + run: | + echo "version=v$(curl -s https://$SITE/version)" >> $GITHUB_OUTPUT + + # The current version bundle melding dance is skipped if the version we're deploying is the same + # as then we're just doing a re-deploy of the same version with potentially different configs. + - name: Download current version for its old bundles + id: current_download + if: steps.current_version.outputs.version != github.ref_name + uses: ./.github/actions/download-verify-element-tarball + with: + tag: ${{ steps.current_version.outputs.version }} + out-file-path: _current_version + + - name: Download target version + uses: ./.github/actions/download-verify-element-tarball + with: + tag: ${{ github.ref_name }} + out-file-path: _deploy + + - name: Merge current bundles into target + if: steps.current_download.outcome == 'success' + run: cp -vnpr _current_version/bundles/* _deploy/bundles/ + + - name: Copy config + run: cp element.io/app/config.json _deploy/config.json + + - name: Populate 404.html + run: echo "404 Not Found" > _deploy/404.html + + - name: Populate _headers + run: cp .github/cfp_headers _deploy/_headers + + - name: Wait for other steps to succeed + uses: t3chguy/wait-on-check-action@18541021811b56544d90e0f073401c2b99e249d6 # fork + with: + ref: ${{ github.sha }} + running-workflow-name: "Deploy to Cloudflare Pages" + repo-token: ${{ secrets.GITHUB_TOKEN }} + wait-interval: 10 + check-regexp: ^((?!SonarCloud|SonarQube|issue|board|label|Release|prepare|GitHub Pages).)*$ + + - name: Deploy to Cloudflare Pages + uses: cloudflare/pages-action@f0a1cd58cd66095dee69bfa18fa5efd1dde93bca # v1 + with: + apiToken: ${{ secrets.CF_PAGES_TOKEN }} + accountId: ${{ secrets.CF_PAGES_ACCOUNT_ID }} + projectName: ${{ env.SITE == 'staging.element.io' && 'element-web-staging' || 'element-web' }} + directory: _deploy + gitHubToken: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/dockerhub.yaml b/.github/workflows/dockerhub.yaml new file mode 100644 index 00000000000..7911cf794a9 --- /dev/null +++ b/.github/workflows/dockerhub.yaml @@ -0,0 +1,79 @@ +name: Dockerhub +on: + workflow_dispatch: {} + push: + tags: [v*] + schedule: + # This job can take a while, and we have usage limits, so just publish develop only twice a day + - cron: "0 7/12 * * *" +concurrency: ${{ github.workflow }}-${{ github.ref_name }} +permissions: {} +jobs: + buildx: + name: Docker Buildx + runs-on: ubuntu-24.04 + environment: dockerhub + permissions: + id-token: write # needed for signing the images with GitHub OIDC Token + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 # needed for docker-package to be able to calculate the version + + - name: Install Cosign + uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3 + + - name: Set up QEMU + uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3 + with: + install: true + + - name: Login to Docker Hub + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Docker meta + id: meta + uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5 + with: + images: | + vectorim/element-web + tags: | + type=ref,event=branch + type=ref,event=tag + flavor: | + latest=${{ contains(github.ref_name, '-rc.') && 'false' || 'auto' }} + + - name: Build and push + id: build-and-push + uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6 + with: + context: . + push: true + platforms: linux/amd64,linux/arm64 + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + + - name: Sign the images with GitHub OIDC Token + env: + DIGEST: ${{ steps.build-and-push.outputs.digest }} + TAGS: ${{ steps.meta.outputs.tags }} + run: | + images="" + for tag in ${TAGS}; do + images+="${tag}@${DIGEST} " + done + cosign sign --yes ${images} + + - name: Update repo description + uses: peter-evans/dockerhub-description@e98e4d1628a5f3be2be7c231e50981aee98723ae # v4 + continue-on-error: true + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + repository: vectorim/element-web diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 00000000000..a301b6daf6f --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,107 @@ +name: Deploy documentation + +on: + push: + branches: [develop] + workflow_dispatch: {} + +permissions: {} + +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + build: + name: GitHub Pages + runs-on: ubuntu-24.04 + steps: + - name: Fetch element-desktop + uses: actions/checkout@v4 + with: + repository: element-hq/element-desktop + path: element-desktop + + - name: Fetch element-web + uses: actions/checkout@v4 + with: + path: element-web + + - name: Fetch matrix-js-sdk + uses: actions/checkout@v4 + with: + repository: matrix-org/matrix-js-sdk + path: matrix-js-sdk + + - uses: actions/setup-node@v4 + with: + cache: "yarn" + cache-dependency-path: element-web/yarn.lock + node-version: "lts/*" + + - name: Generate automations docs + working-directory: element-web + run: | + yarn install --frozen-lockfile + yarn ts-node ./scripts/gen-workflow-mermaid.ts ../element-desktop ../element-web ../matrix-js-sdk > docs/automations.md + echo "- [Automations](automations.md)" >> docs/SUMMARY.md + + - name: Setup mdBook + uses: peaceiris/actions-mdbook@v2 + with: + mdbook-version: "0.4.10" + + - name: Install mdbook extensions + run: cargo install mdbook-combiner mdbook-mermaid + + - name: Prepare docs + run: | + mkdir docs + + mv element-desktop/README.md element-desktop/docs/ + mv element-desktop/docs "docs/Element Desktop" + + mv element-web/README.md element-web/docs/ + mv element-web/docs/lib docs/ + mv element-web/docs "docs/Element Web" + + mv matrix-js-sdk/README.md matrix-js-sdk/docs/ + mv matrix-js-sdk/docs "docs/Matrix JS SDK" + + sed -i -e 's/\.\.\/README.md/README.md/' docs/**/SUMMARY.md + + mdbook-combiner -m docs + sed -i -E 's/^\t# (.+)$/- [\1]()/gm;t' SUMMARY.md + sed -i -E 's/^- \[(.+)]\(<>\)$/---\n# \1/gm;t' SUMMARY.md + sed -i -E 's/\t- \[Introduction]/- [Introduction]/gm;t' SUMMARY.md + + cat < docs/SUMMARY.md + # Summary + - [Introduction]() + + EOF + cat SUMMARY.md >> docs/SUMMARY.md + + mv element-web/book.toml . + + - name: Build docs + run: mdbook build + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + path: ./book + + deploy: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-24.04 + permissions: + pages: write + id-token: write + needs: build + steps: + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/end-to-end-tests-netlify.yaml b/.github/workflows/end-to-end-tests-netlify.yaml new file mode 100644 index 00000000000..e25994ec9df --- /dev/null +++ b/.github/workflows/end-to-end-tests-netlify.yaml @@ -0,0 +1,46 @@ +# Triggers after the playwright tests have finished, +# taking the artifact and uploading it to Netlify for easier viewing +name: Upload End to End Test report to Netlify +on: + workflow_run: + workflows: ["End to End Tests"] + types: + - completed + +concurrency: + group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch || github.run_id }} + cancel-in-progress: ${{ github.event.workflow_run.event == 'pull_request' }} + +permissions: {} + +jobs: + report: + if: github.event.workflow_run.conclusion != 'cancelled' + name: Report results + runs-on: ubuntu-24.04 + environment: Netlify + permissions: + statuses: write + deployments: write + actions: read + steps: + - name: Download HTML report + uses: actions/download-artifact@v4 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + run-id: ${{ github.event.workflow_run.id }} + name: html-report + path: playwright-report + + - name: 📤 Deploy to Netlify + uses: matrix-org/netlify-pr-preview@v3 + with: + path: playwright-report + owner: ${{ github.event.workflow_run.head_repository.owner.login }} + branch: ${{ github.event.workflow_run.head_branch }} + revision: ${{ github.event.workflow_run.head_sha }} + token: ${{ secrets.NETLIFY_AUTH_TOKEN }} + site_id: ${{ vars.NETLIFY_SITE_ID }} + desc: Playwright Report + deployment_env: EndToEndTests + prefix: "e2e-" diff --git a/.github/workflows/end-to-end-tests.yaml b/.github/workflows/end-to-end-tests.yaml new file mode 100644 index 00000000000..1a31f750656 --- /dev/null +++ b/.github/workflows/end-to-end-tests.yaml @@ -0,0 +1,191 @@ +# Produce a build of element-web with this version of react-sdk +# and any matching branches of element-web and js-sdk, output it +# as an artifact and run end-to-end tests. +name: End to End Tests +on: + pull_request: {} + merge_group: + types: [checks_requested] + push: + branches: [develop, master] + repository_dispatch: + types: [element-web-notify] + + # support triggering from other workflows + workflow_call: + inputs: + skip: + type: boolean + required: false + default: false + description: "A boolean to skip the playwright check itself while still creating the passing check. Useful when only running in Merge Queues." + + matrix-js-sdk-sha: + type: string + required: false + description: "The Git SHA of matrix-js-sdk to build against. By default, will use a matching branch name if it exists, or develop." + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} + cancel-in-progress: true + +env: + # fetchdep.sh needs to know our PR number + PR_NUMBER: ${{ github.event.pull_request.number }} + +permissions: {} # No permissions required + +jobs: + build: + name: "Build Element-Web" + runs-on: ubuntu-24.04 + if: inputs.skip != true + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + repository: element-hq/element-web + + - uses: actions/setup-node@v4 + with: + cache: "yarn" + node-version: "lts/*" + + - name: Fetch layered build + id: layered_build + env: + # tell layered.sh to check out the right sha of the JS-SDK & EW, if they were given one + JS_SDK_GITHUB_BASE_REF: ${{ inputs.matrix-js-sdk-sha }} + run: | + scripts/layered.sh + JSSDK_SHA=$(git -C matrix-js-sdk rev-parse --short=12 HEAD) + VECTOR_SHA=$(git rev-parse --short=12 HEAD) + echo "VERSION=$VECTOR_SHA--js-$JSSDK_SHA" >> $GITHUB_OUTPUT + + - name: Copy config + run: cp element.io/develop/config.json config.json + + - name: Build + env: + CI_PACKAGE: true + VERSION: "${{ steps.layered_build.outputs.VERSION }}" + run: | + yarn build + + - name: Upload Artifact + uses: actions/upload-artifact@v4 + with: + name: webapp + path: webapp + retention-days: 1 + + playwright: + name: "Run Tests ${{ matrix.runner }}/${{ strategy.job-total }}" + needs: build + if: inputs.skip != true + runs-on: ubuntu-22.04 + permissions: + actions: read + issues: read + pull-requests: read + strategy: + fail-fast: false + matrix: + # Run multiple instances in parallel to speed up the tests + runner: [1, 2, 3, 4, 5, 6] + steps: + - uses: actions/checkout@v4 + with: + persist-credentials: false + repository: element-hq/element-web + + - name: 📥 Download artifact + uses: actions/download-artifact@v4 + with: + name: webapp + path: webapp + + - uses: actions/setup-node@v4 + with: + cache: "yarn" + cache-dependency-path: yarn.lock + node-version: "lts/*" + + - name: Install dependencies + run: yarn install --frozen-lockfile + + - name: Get installed Playwright version + id: playwright + run: echo "version=$(yarn list --pattern @playwright/test --depth=0 --json --non-interactive --no-progress | jq -r '.data.trees[].name')" >> $GITHUB_OUTPUT + + - name: Cache playwright binaries + uses: actions/cache@v4 + id: playwright-cache + with: + path: | + ~/.cache/ms-playwright + key: ${{ runner.os }}-playwright-${{ steps.playwright.outputs.version }} + + - name: Install Playwright browsers + if: steps.playwright-cache.outputs.cache-hit != 'true' + run: yarn playwright install --with-deps + + - name: Run Playwright tests + run: yarn playwright test --shard ${{ matrix.runner }}/${{ strategy.job-total }} + + - name: Upload blob report to GitHub Actions Artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: all-blob-reports-${{ matrix.runner }} + path: blob-report + retention-days: 1 + + complete: + name: end-to-end-tests + needs: playwright + if: always() + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + if: inputs.skip != true + with: + persist-credentials: false + repository: element-hq/element-web + + - uses: actions/setup-node@v4 + if: inputs.skip != true + with: + cache: "yarn" + node-version: "lts/*" + + - name: Install dependencies + if: inputs.skip != true + run: yarn install --frozen-lockfile + + - name: Download blob reports from GitHub Actions Artifacts + if: inputs.skip != true + uses: actions/download-artifact@v4 + with: + pattern: all-blob-reports-* + path: all-blob-reports + merge-multiple: true + + - name: Merge into HTML Report + if: inputs.skip != true + run: yarn playwright merge-reports --reporter=html,./playwright/flaky-reporter.ts,./playwright/stale-screenshot-reporter.ts ./all-blob-reports + env: + # Only pass creds to the flaky-reporter on main branch runs + GITHUB_TOKEN: ${{ github.ref_name == 'develop' && secrets.ELEMENT_BOT_TOKEN || '' }} + + # Upload the HTML report even if one of our reporters fails, this can happen when stale screenshots are detected + - name: Upload HTML report + if: always() && inputs.skip != true + uses: actions/upload-artifact@v4 + with: + name: html-report + path: playwright-report + retention-days: 14 + + - if: needs.playwright.result != 'skipped' && needs.playwright.result != 'success' + run: exit 1 diff --git a/.github/workflows/issue_closed.yml b/.github/workflows/issue_closed.yml new file mode 100644 index 00000000000..2cffae0011a --- /dev/null +++ b/.github/workflows/issue_closed.yml @@ -0,0 +1,157 @@ +# For duplicate issues, ensure the close type is right (not planned), update it if not +# For all closed (completed) issues, cascade the closure onto any referenced rageshakes +# For all closed (not planned) issues, comment on rageshakes to move them into the canonical issue if one exists +on: + issues: + types: [closed] +permissions: {} # We use ELEMENT_BOT_TOKEN instead +jobs: + tidy: + name: Tidy closed issues + runs-on: ubuntu-24.04 + steps: + - uses: actions/github-script@v7 + id: main + with: + # PAT needed as the GITHUB_TOKEN won't be able to see cross-references from other orgs (matrix-org) + github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} + script: | + const variables = { + owner: context.repo.owner, + name: context.repo.repo, + number: context.issue.number, + }; + + const query = `query($owner:String!, $name:String!, $number:Int!) { + repository(owner: $owner, name: $name) { + issue(number: $number) { + stateReason, + timelineItems(first: 100, itemTypes: [MARKED_AS_DUPLICATE_EVENT, UNMARKED_AS_DUPLICATE_EVENT, CROSS_REFERENCED_EVENT]) { + edges { + node { + __typename + ... on MarkedAsDuplicateEvent { + canonical { + ... on Issue { + repository { + nameWithOwner + } + number + } + ... on PullRequest { + repository { + nameWithOwner + } + number + } + } + } + ... on UnmarkedAsDuplicateEvent { + canonical { + ... on Issue { + repository { + nameWithOwner + } + number + } + ... on PullRequest { + repository { + nameWithOwner + } + number + } + } + } + ... on CrossReferencedEvent { + source { + ... on Issue { + repository { + nameWithOwner + } + number + } + ... on PullRequest { + repository { + nameWithOwner + } + number + } + } + } + } + } + } + } + } + }`; + + const result = await github.graphql(query, variables); + const { stateReason, timelineItems: { edges } } = result.repository.issue; + + const RAGESHAKE_OWNER = "matrix-org"; + const RAGESHAKE_REPO = "element-web-rageshakes"; + const rageshakes = new Set(); + const duplicateOf = new Set(); + + console.log("Edges: ", JSON.stringify(edges)); + + for (const { node } of edges) { + switch(node.__typename) { + case "MarkedAsDuplicateEvent": + duplicateOf.add(node.canonical.repository.nameWithOwner + "#" + node.canonical.number); + break; + case "UnmarkedAsDuplicateEvent": + duplicateOf.remove(node.canonical.repository.nameWithOwner + "#" + node.canonical.number); + break; + case "CrossReferencedEvent": + if (node.source.repository.nameWithOwner === (RAGESHAKE_OWNER + "/" + RAGESHAKE_REPO)) { + rageshakes.add(node.source.number); + } + break; + } + } + + console.log("Duplicate of: ", duplicateOf); + console.log("Found rageshakes: ", rageshakes); + + if (duplicateOf.size) { + const body = Array.from(duplicateOf).join("\n"); + + // Comment on all rageshakes to create relationship to the issue this was closed as duplicate of + for (const rageshake of rageshakes) { + github.rest.issues.createComment({ + owner: RAGESHAKE_OWNER, + repo: RAGESHAKE_REPO, + issue_number: rageshake, + body, + }); + } + + // Duplicate was closed with wrong reason, fix it + if (stateReason === "COMPLETED") { + core.setOutput("closeAsNotPlanned", "true"); + } + } else { + // This issue was closed, close all related rageshakes + for (const rageshake of rageshakes) { + github.rest.issues.update({ + owner: RAGESHAKE_OWNER, + repo: RAGESHAKE_REPO, + issue_number: rageshake, + state: "closed", + }); + } + } + - uses: actions/github-script@v7 + name: Close duplicate as Not Planned + if: steps.main.outputs.closeAsNotPlanned + with: + # We do this step separately, and with the default token so as to not re-trigger this workflow when re-closing + script: | + await github.graphql(`mutation($id:ID!) { + closeIssue(input: { issueId:$id, stateReason:NOT_PLANNED }) { + clientMutationId + } + }`, { + id: context.payload.issue.node_id, + }); diff --git a/.github/workflows/localazy_download.yaml b/.github/workflows/localazy_download.yaml new file mode 100644 index 00000000000..435b8154ba5 --- /dev/null +++ b/.github/workflows/localazy_download.yaml @@ -0,0 +1,11 @@ +name: Localazy Download +on: + workflow_dispatch: {} + schedule: + - cron: "0 6 * * 1,3,5" # Every Monday, Wednesday and Friday at 6am UTC +permissions: {} # We use ELEMENT_BOT_TOKEN instead +jobs: + download: + uses: matrix-org/matrix-web-i18n/.github/workflows/localazy_download.yaml@main + secrets: + ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} diff --git a/.github/workflows/localazy_upload.yaml b/.github/workflows/localazy_upload.yaml new file mode 100644 index 00000000000..8cb77439680 --- /dev/null +++ b/.github/workflows/localazy_upload.yaml @@ -0,0 +1,12 @@ +name: Localazy Upload +on: + push: + branches: [develop] + paths: + - "src/i18n/strings/en_EN.json" +permissions: {} # No permissions needed +jobs: + upload: + uses: matrix-org/matrix-web-i18n/.github/workflows/localazy_upload.yaml@main + secrets: + LOCALAZY_WRITE_KEY: ${{ secrets.LOCALAZY_WRITE_KEY }} diff --git a/.github/workflows/netlify.yaml b/.github/workflows/netlify.yaml new file mode 100644 index 00000000000..63bac7d33f5 --- /dev/null +++ b/.github/workflows/netlify.yaml @@ -0,0 +1,51 @@ +# Triggers after the layered build has finished, taking the artifact +# and uploading it to netlify +name: Upload Preview Build to Netlify +on: + workflow_run: + workflows: ["End to End Tests"] + types: + - completed +jobs: + deploy: + if: github.event.workflow_run.conclusion != 'cancelled' && github.event.workflow_run.event == 'pull_request' + runs-on: ubuntu-24.04 + environment: Netlify + permissions: + actions: read + deployments: write + steps: + - name: 📝 Create Deployment + uses: bobheadxi/deployments@648679e8e4915b27893bd7dbc35cb504dc915bc8 # v1 + id: deployment + with: + step: start + token: ${{ secrets.GITHUB_TOKEN }} + env: Netlify + ref: ${{ github.event.workflow_run.head_sha }} + desc: | + Do you trust the author of this PR? Maybe this build will steal your keys or give you malware. + Exercise caution. Use test accounts. + + - name: 📥 Download artifact + uses: actions/download-artifact@v4 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + run-id: ${{ github.event.workflow_run.id }} + name: webapp + path: webapp + + - name: 📤 Deploy to Netlify + uses: matrix-org/netlify-pr-preview@v3 + with: + path: webapp + owner: ${{ github.event.workflow_run.head_repository.owner.login }} + branch: ${{ github.event.workflow_run.head_branch }} + revision: ${{ github.event.workflow_run.head_sha }} + token: ${{ secrets.NETLIFY_AUTH_TOKEN }} + site_id: ${{ vars.NETLIFY_SITE_ID }} + deployment_env: ${{ steps.deployment.outputs.env }} + deployment_id: ${{ steps.deployment.outputs.deployment_id }} + desc: | + Do you trust the author of this PR? Maybe this build will steal your keys or give you malware. + Exercise caution. Use test accounts. diff --git a/.github/workflows/pending-reviews.yaml b/.github/workflows/pending-reviews.yaml new file mode 100644 index 00000000000..c96ed3f17e8 --- /dev/null +++ b/.github/workflows/pending-reviews.yaml @@ -0,0 +1,92 @@ +name: Pending reviews automation +on: + # The bot exceeded its API rate limit. Disabling for now (adding workflow dispatch so the workflow file stays valid & we can test to see if it starts working again) + workflow_dispatch: {} + # We run it on a schedule instead of on pull_request_* events to not create confusing messaging in the PR + #schedule: + # - cron: "*/10 * * * *" +concurrency: ${{ github.workflow }} +permissions: {} # We use ELEMENT_BOT_TOKEN instead +jobs: + bot: + name: Pending reviews bot + runs-on: ubuntu-24.04 + environment: Matrix + env: + URL: "https://github.com/pulls?q=is%3Apr+is%3Aopen+repo%3Amatrix-org%2Fmatrix-js-sdk+repo%3Amatrix-org%2Fmatrix-react-sdk+repo%3Aelement-hq%2Felement-web+repo%3Aelement-hq%2Felement-desktop+review-requested%3A%40me+sort%3Aupdated-desc+" + RELEASE_BLOCKERS_URL: "https://github.com/pulls?q=is%3Aopen+repo%3Amatrix-org%2Fmatrix-js-sdk+repo%3Amatrix-org%2Fmatrix-react-sdk+repo%3Aelement-hq%2Felement-web+repo%3Aelement-hq%2Felement-desktop+sort%3Aupdated-desc+label%3AX-Release-Blocker+" + steps: + - uses: actions/github-script@v7 + env: + HS_URL: ${{ secrets.BETABOT_HS_URL }} + ROOM_ID: ${{ secrets.ROOM_ID }} + TOKEN: ${{ secrets.BETABOT_ACCESS_TOKEN }} + with: + # PAT needed as the GITHUB_TOKEN won't be able to see cross-references from other orgs (matrix-org) + github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} + script: | + const { HS_URL, ROOM_ID, TOKEN, URL, RELEASE_BLOCKERS_URL } = process.env; + + async function updateCounter(counter, link, severity, title, value, clearOnZero) { + const apiUrl = `${HS_URL}/_matrix/client/v3/rooms/${ROOM_ID}/state/re.jki.counter/${counter}`; + const headers = { + "Content-Type": "application/json", + "Authorization": `Bearer ${TOKEN}`, + }; + const res = await fetch(apiUrl, { + method: "GET", + headers, + }); + + const data = await res.json(); + + if (data.value === issueCount) { + console.log("Pending review count already correct"); + return; + } + + let body = {}; + if (issueCount || !clearOnZero) { + body = JSON.stringify({ + link, + severity, + title, + value, + }); + } + + await fetch(apiUrl, { + method: "PUT", + body, + headers, + }); + } + + const repos = [ + "element-hq/element-desktop", + "element-hq/element-web", + "matrix-org/matrix-js-sdk", + ]; + const teams = [ + "matrix-org/element-web-team", + "matrix-org/element-web-reviewers", + "element-hq/element-web-team", + "element-hq/element-web-reviewers", + ]; + + let issueCount = 0; + for (const team of teams) { + const org = team.split("/", 2)[0]; + const reposInOrg = repos.filter(repo => repo.startsWith(org + "/")); + const { data } = await github.rest.search.issuesAndPullRequests({ + q: `is:pr is:open review:required ${reposInOrg.map(r => `repo:${r}`).join(" ")} team-review-requested:${team}`, + }); + issueCount += data.total_count; + } + await updateCounter("gh_reviews", URL, "warning", "Pending reviews", issueCount); + + const { data } = await github.rest.search.issuesAndPullRequests({ + q: `is:open ${repos.map(repo => `repo:${repo}`).join(" ")} label:X-Release-Blocker`, + }); + const blockerCount = data.total_count; + await updateCounter("release_blockers", RELEASE_BLOCKERS_URL, "alert", "Release Blockers", blockerCount, true); diff --git a/.github/workflows/playwright-image-updates.yaml b/.github/workflows/playwright-image-updates.yaml new file mode 100644 index 00000000000..1613b42dfb7 --- /dev/null +++ b/.github/workflows/playwright-image-updates.yaml @@ -0,0 +1,48 @@ +name: Update Playwright docker images +on: + workflow_dispatch: {} + schedule: + - cron: "0 6 * * *" # Every day at 6am UTC +permissions: {} +jobs: + update: + runs-on: ubuntu-24.04 + permissions: + pull-requests: write + steps: + - uses: actions/checkout@v4 + + - name: Update synapse image + run: | + docker pull "$IMAGE" + INSPECT=$(docker inspect --format='{{index .RepoDigests 0}}' "$IMAGE") + DIGEST=${INSPECT#*@} + sed -i "s/const DOCKER_TAG.*/const DOCKER_TAG = \"develop@$DIGEST\";/" playwright/plugins/homeserver/synapse/index.ts + env: + IMAGE: ghcr.io/element-hq/synapse:develop + + - name: Create Pull Request + id: cpr + uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7 + with: + token: ${{ secrets.ELEMENT_BOT_TOKEN }} + branch: actions/playwright-image-updates + delete-branch: true + title: Playwright Docker image updates + labels: | + T-Task + + - name: Enable automerge + run: gh pr merge --merge --auto "$PR_NUMBER" + if: steps.cpr.outputs.pull-request-operation == 'created' + env: + GH_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} + PR_NUMBER: ${{ steps.cpr.outputs.pull-request-number }} + + - name: Enable autoapprove + run: | + gh pr review --approve "$PR_NUMBER" + if: steps.cpr.outputs.pull-request-operation == 'created' + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ steps.cpr.outputs.pull-request-number }} diff --git a/.github/workflows/pull_request.yaml b/.github/workflows/pull_request.yaml new file mode 100644 index 00000000000..2f97ccbbb41 --- /dev/null +++ b/.github/workflows/pull_request.yaml @@ -0,0 +1,14 @@ +name: Pull Request +on: + pull_request_target: + types: [opened, edited, labeled, unlabeled, synchronize] + merge_group: + types: [checks_requested] +permissions: {} +jobs: + action: + uses: matrix-org/matrix-js-sdk/.github/workflows/pull_request.yaml@develop + permissions: + pull-requests: read + secrets: + ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} diff --git a/.github/workflows/pull_request_base_branch.yaml b/.github/workflows/pull_request_base_branch.yaml new file mode 100644 index 00000000000..6610ee48791 --- /dev/null +++ b/.github/workflows/pull_request_base_branch.yaml @@ -0,0 +1,17 @@ +name: Pull Request Base Branch +on: + pull_request: + types: [opened, edited, synchronize] +permissions: {} # No permissions required +jobs: + check_base_branch: + name: Check PR base branch + runs-on: ubuntu-24.04 + steps: + - uses: actions/github-script@v7 + with: + script: | + const baseBranch = context.payload.pull_request.base.ref; + if (!['develop', 'staging'].includes(baseBranch) && !baseBranch.startsWith('feat/')) { + core.setFailed(`Invalid base branch: ${baseBranch}`); + } diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml new file mode 100644 index 00000000000..c4bf8e6ab30 --- /dev/null +++ b/.github/workflows/release-drafter.yml @@ -0,0 +1,12 @@ +name: Release Drafter +on: + push: + branches: [staging] + workflow_dispatch: {} +concurrency: ${{ github.workflow }} +permissions: {} +jobs: + draft: + permissions: + contents: write + uses: matrix-org/matrix-js-sdk/.github/workflows/release-drafter-workflow.yml@develop diff --git a/.github/workflows/release-gitflow.yml b/.github/workflows/release-gitflow.yml new file mode 100644 index 00000000000..128c6a1e05d --- /dev/null +++ b/.github/workflows/release-gitflow.yml @@ -0,0 +1,15 @@ +# Gitflow merge-back master->develop +name: Merge master -> develop +on: + push: + branches: [master] +concurrency: ${{ github.repository }}-${{ github.workflow }} +permissions: {} # We use ELEMENT_BOT_TOKEN instead +jobs: + merge: + uses: matrix-org/matrix-js-sdk/.github/workflows/release-gitflow.yml@develop + secrets: + ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} + with: + dependencies: | + matrix-js-sdk diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000000..2ecc4a46626 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,68 @@ +name: Release Process +on: + workflow_dispatch: + inputs: + mode: + description: What type of release + required: true + default: rc + type: choice + options: + - rc + - final +concurrency: ${{ github.workflow }} +permissions: {} +jobs: + release: + uses: matrix-org/matrix-js-sdk/.github/workflows/release-make.yml@develop + permissions: + contents: write + issues: write + secrets: + ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} + GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + with: + final: ${{ inputs.mode == 'final' }} + gpg-fingerprint: ${{ vars.GPG_FINGERPRINT }} + asset-path: dist/*.tar.gz + expected-asset-count: 3 + + notify-downstream: + name: Trigger release drafter downstream + needs: release + runs-on: ubuntu-24.04 + steps: + - name: Notify element-desktop repo that element-web release has completed to re-trigger release-drafter + uses: benc-uk/workflow-dispatch@e2e5e9a103e331dad343f381a29e654aea3cf8fc # v1 + with: + workflow: release-drafter.yml + repo: element-hq/element-desktop + ref: staging + # Required when using the `repo` option. Either a PAT or a token generated from the GitHub app or CLI + token: "${{ secrets.ELEMENT_BOT_TOKEN }}" + + check: + name: Post release checks + needs: release + runs-on: ubuntu-24.04 + permissions: + checks: read + steps: + - name: Wait for dockerhub + uses: t3chguy/wait-on-check-action@18541021811b56544d90e0f073401c2b99e249d6 # fork + with: + ref: master + repo-token: ${{ secrets.GITHUB_TOKEN }} + wait-interval: 10 + check-name: "Docker Buildx" + allowed-conclusions: success + + - name: Wait for debian package + uses: t3chguy/wait-on-check-action@18541021811b56544d90e0f073401c2b99e249d6 # fork + with: + ref: master + repo-token: ${{ secrets.GITHUB_TOKEN }} + wait-interval: 10 + check-name: Build package + allowed-conclusions: success diff --git a/.github/workflows/release_prepare.yml b/.github/workflows/release_prepare.yml new file mode 100644 index 00000000000..b655bb42061 --- /dev/null +++ b/.github/workflows/release_prepare.yml @@ -0,0 +1,111 @@ +name: Cut branches +on: + workflow_dispatch: + inputs: + element-desktop: + description: Prepare element-desktop + required: true + type: boolean + default: true + element-web: + description: Prepare element-web + required: true + type: boolean + default: true + matrix-js-sdk: + description: Prepare matrix-js-sdk + required: true + type: boolean + default: true +permissions: {} # Uses ELEMENT_BOT_TOKEN instead +jobs: + prepare: + runs-on: ubuntu-24.04 + env: + # The order is specified bottom-up to avoid any races for allchange + REPOS: matrix-js-sdk element-web element-desktop + steps: + - name: Checkout Element Desktop + uses: actions/checkout@v4 + if: inputs.element-desktop + with: + repository: element-hq/element-desktop + path: element-desktop + ref: staging + fetch-depth: 0 + fetch-tags: true + token: ${{ secrets.ELEMENT_BOT_TOKEN }} + - name: Checkout Element Web + uses: actions/checkout@v4 + if: inputs.element-web + with: + repository: element-hq/element-web + path: element-web + ref: staging + fetch-depth: 0 + fetch-tags: true + token: ${{ secrets.ELEMENT_BOT_TOKEN }} + - name: Checkout Matrix JS SDK + uses: actions/checkout@v4 + if: inputs.matrix-js-sdk + with: + repository: matrix-org/matrix-js-sdk + path: matrix-js-sdk + ref: staging + fetch-depth: 0 + fetch-tags: true + token: ${{ secrets.ELEMENT_BOT_TOKEN }} + + - name: Prepare Git + run: | + git config --global user.email "releases@riot.im" + git config --global user.name "RiotRobot" + + - name: Merge Element Desktop + if: inputs.element-desktop + run: | + git -C "element-desktop" merge origin/develop + - name: Merge Element Web + if: inputs.element-web + run: | + git -C "element-web" merge origin/develop + - name: Merge JS SDK + if: inputs.matrix-js-sdk + run: | + git -C "matrix-js-sdk" merge origin/develop + + - name: Push staging + run: for REPO in $REPOS; do [ -d "$REPO" ] && git -C "$REPO" push origin staging; done + + - name: Wait for matrix-js-sdk draft + if: inputs.matrix-js-sdk + uses: t3chguy/wait-on-check-action@18541021811b56544d90e0f073401c2b99e249d6 # fork + with: + ref: staging + repo: matrix-org/matrix-js-sdk + repo-token: ${{ secrets.ELEMENT_BOT_TOKEN }} + wait-interval: 10 + check-name: draft + allowed-conclusions: success + + - name: Wait for element-web draft + if: inputs.element-web + uses: t3chguy/wait-on-check-action@18541021811b56544d90e0f073401c2b99e249d6 # fork + with: + ref: staging + repo: element-hq/element-web + repo-token: ${{ secrets.ELEMENT_BOT_TOKEN }} + wait-interval: 10 + check-name: draft + allowed-conclusions: success + + - name: Wait for element-desktop draft + if: inputs.element-desktop + uses: t3chguy/wait-on-check-action@18541021811b56544d90e0f073401c2b99e249d6 # fork + with: + ref: staging + repo: element-hq/element-desktop + repo-token: ${{ secrets.ELEMENT_BOT_TOKEN }} + wait-interval: 10 + check-name: draft + allowed-conclusions: success diff --git a/.github/workflows/sonarqube.yml b/.github/workflows/sonarqube.yml new file mode 100644 index 00000000000..0ee457bac21 --- /dev/null +++ b/.github/workflows/sonarqube.yml @@ -0,0 +1,24 @@ +name: SonarQube +on: + workflow_run: + workflows: ["Tests"] + types: + - completed +concurrency: + group: ${{ github.workflow }}-${{ github.event.workflow_run.head_branch }} + cancel-in-progress: true +permissions: {} +jobs: + sonarqube: + name: 🩻 SonarQube + if: github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event != 'merge_group' + uses: matrix-org/matrix-js-sdk/.github/workflows/sonarcloud.yml@develop + permissions: + actions: read + statuses: write + id-token: write # sonar + secrets: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} + with: + sharded: true diff --git a/.github/workflows/static_analysis.yaml b/.github/workflows/static_analysis.yaml new file mode 100644 index 00000000000..b7c02c3f2e9 --- /dev/null +++ b/.github/workflows/static_analysis.yaml @@ -0,0 +1,140 @@ +name: Static Analysis +on: + pull_request: {} + push: + branches: [develop, master] + merge_group: + types: [checks_requested] + repository_dispatch: + types: [element-web-notify] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} + cancel-in-progress: true + +env: + # These must be set for fetchdep.sh to get the right branch + REPOSITORY: ${{ github.repository }} + PR_NUMBER: ${{ github.event.pull_request.number }} + +permissions: {} # No permissions required + +jobs: + ts_lint: + name: "Typescript Syntax Check" + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + cache: "yarn" + node-version: "lts/*" + + - name: Install Dependencies + run: "./scripts/layered.sh" + + - name: Typecheck + run: "yarn run lint:types" + + i18n_lint: + name: "i18n Check" + uses: matrix-org/matrix-web-i18n/.github/workflows/i18n_check.yml@main + permissions: + pull-requests: read + with: + hardcoded-words: "Element" + allowed-hardcoded-keys: | + console_dev_note + labs|element_call_video_rooms + labs|feature_disable_call_per_sender_encryption + voip|element_call + error|invalid_json + error|misconfigured + welcome_to_element + + rethemendex_lint: + name: "Rethemendex Check" + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + + - run: ./res/css/rethemendex.sh + + - run: git diff --exit-code + + js_lint: + name: "ESLint" + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + cache: "yarn" + node-version: "lts/*" + + # Does not need branch matching as only analyses this layer + - name: Install Deps + run: "yarn install --frozen-lockfile" + + - name: Run Linter + run: "yarn run lint:js" + + style_lint: + name: "Style Lint" + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + cache: "yarn" + node-version: "lts/*" + + # Does not need branch matching as only analyses this layer + - name: Install Deps + run: "yarn install" + + - name: Run Linter + run: "yarn run lint:style" + + workflow_lint: + name: "Workflow Lint" + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + cache: "yarn" + node-version: "lts/*" + + # Does not need branch matching as only analyses this layer + - name: Install Deps + run: "yarn install --frozen-lockfile" + + - name: Run Linter + run: "yarn lint:workflows" + + analyse_dead_code: + name: "Analyse Dead Code" + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + cache: "yarn" + node-version: "lts/*" + + - name: Install Deps + run: "yarn install --frozen-lockfile" + + - name: Run linter + run: "yarn run lint:knip" + + - name: Install Deps + run: "scripts/layered.sh" + + - name: Dead Code Analysis + run: "yarn run analyse:unused-exports" diff --git a/.github/workflows/sync-labels.yml b/.github/workflows/sync-labels.yml new file mode 100644 index 00000000000..fa1be485bb0 --- /dev/null +++ b/.github/workflows/sync-labels.yml @@ -0,0 +1,24 @@ +name: Sync labels +on: + workflow_dispatch: {} + schedule: + - cron: "0 1 * * *" # 1am every day + push: + branches: + - develop + paths: + - .github/labels.yml + +permissions: {} # We use ELEMENT_BOT_TOKEN instead + +jobs: + sync-labels: + uses: element-hq/element-meta/.github/workflows/sync-labels.yml@develop + with: + LABELS: | + element-hq/element-meta + .github/labels.yml + DELETE: true + WET: true + secrets: + ELEMENT_BOT_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 00000000000..14fd5ffd648 --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,114 @@ +name: Tests +on: + pull_request: {} + merge_group: + types: [checks_requested] + push: + branches: [develop, master] + repository_dispatch: + types: [element-web-notify] + workflow_call: + inputs: + disable_coverage: + type: boolean + required: false + description: "Specify true to skip generating and uploading coverage for tests" + matrix-js-sdk-sha: + type: string + required: false + description: "The matrix-js-sdk SHA to use" +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} + cancel-in-progress: true + +env: + ENABLE_COVERAGE: ${{ github.event_name != 'merge_group' && inputs.disable_coverage != 'true' }} + # fetchdep.sh needs to know our PR number + PR_NUMBER: ${{ github.event.pull_request.number }} + +permissions: {} + +jobs: + jest: + name: Jest + runs-on: ubuntu-24.04 + strategy: + fail-fast: false + matrix: + # Run multiple instances in parallel to speed up the tests + runner: [1, 2] + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + repository: ${{ inputs.matrix-js-sdk-sha && 'element-hq/element-web' || github.repository }} + + - name: Yarn cache + uses: actions/setup-node@v4 + with: + node-version: "lts/*" + cache: "yarn" + + - name: Install Deps + run: "./scripts/layered.sh" + env: + JS_SDK_GITHUB_BASE_REF: ${{ inputs.matrix-js-sdk-sha }} + + - name: Jest Cache + uses: actions/cache@v4 + with: + path: /tmp/jest_cache + key: ${{ hashFiles('**/yarn.lock') }} + + - name: Get number of CPU cores + id: cpu-cores + uses: SimenB/github-actions-cpu-cores@97ba232459a8e02ff6121db9362b09661c875ab8 # v2 + + - name: Run tests + run: | + yarn test \ + --coverage=${{ env.ENABLE_COVERAGE }} \ + --ci \ + --max-workers ${{ steps.cpu-cores.outputs.count }} \ + --shard ${{ matrix.runner }}/${{ strategy.job-total }} \ + --cacheDirectory /tmp/jest_cache + env: + JEST_SONAR_UNIQUE_OUTPUT_NAME: true + + # tell jest to use coloured output + FORCE_COLOR: true + + - name: Move coverage files into place + if: env.ENABLE_COVERAGE == 'true' + run: mv coverage/lcov.info coverage/${{ steps.setupNode.outputs.node-version }}-${{ matrix.runner }}.lcov.info + + - name: Upload Artifact + if: env.ENABLE_COVERAGE == 'true' + uses: actions/upload-artifact@v4 + with: + name: coverage-${{ matrix.runner }} + path: | + coverage + !coverage/lcov-report + + complete: + name: jest-tests + needs: jest + if: always() + runs-on: ubuntu-24.04 + permissions: + statuses: write + steps: + - if: needs.jest.result != 'skipped' && needs.jest.result != 'success' + run: exit 1 + + - name: Skip SonarCloud in merge queue + if: github.event_name == 'merge_group' || inputs.disable_coverage == 'true' + uses: guibranco/github-status-action-v2@1f26a0237cd1a57626fbb5a0eb2494c9b8797d07 + with: + authToken: ${{ secrets.GITHUB_TOKEN }} + state: success + description: SonarCloud skipped + context: SonarCloud Code Analysis + sha: ${{ github.sha }} + target_url: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }} diff --git a/.github/workflows/triage-assigned.yml b/.github/workflows/triage-assigned.yml new file mode 100644 index 00000000000..e43eb946183 --- /dev/null +++ b/.github/workflows/triage-assigned.yml @@ -0,0 +1,20 @@ +name: Move issued assigned to specific team members to their boards + +on: + issues: + types: [assigned] + +permissions: {} # We use ELEMENT_BOT_TOKEN instead + +jobs: + web-app-team: + runs-on: ubuntu-24.04 + if: | + contains(github.event.issue.assignees.*.login, 't3chguy') || + contains(github.event.issue.assignees.*.login, 'andybalaam') || + contains(github.event.issue.assignees.*.login, 'MidhunSureshR') + steps: + - uses: actions/add-to-project@main + with: + project-url: https://github.com/orgs/element-hq/projects/67 + github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} diff --git a/.github/workflows/triage-incoming.yml b/.github/workflows/triage-incoming.yml new file mode 100644 index 00000000000..b084b4d55eb --- /dev/null +++ b/.github/workflows/triage-incoming.yml @@ -0,0 +1,16 @@ +name: Move new issues into Issue triage board + +on: + issues: + types: [opened] + +permissions: {} # We use ELEMENT_BOT_TOKEN instead + +jobs: + automate-project-columns: + runs-on: ubuntu-24.04 + steps: + - uses: actions/add-to-project@main + with: + project-url: https://github.com/orgs/element-hq/projects/120 + github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} diff --git a/.github/workflows/triage-labelled.yml b/.github/workflows/triage-labelled.yml new file mode 100644 index 00000000000..2cb05a8bcff --- /dev/null +++ b/.github/workflows/triage-labelled.yml @@ -0,0 +1,178 @@ +name: Move labelled issues to correct projects + +on: + issues: + types: [labeled] + workflow_call: + secrets: + ELEMENT_BOT_TOKEN: + required: true + +permissions: {} # We use ELEMENT_BOT_TOKEN instead + +jobs: + apply_Z-Labs_label: + name: Add Z-Labs label for features behind labs flags + runs-on: ubuntu-24.04 + if: > + contains(github.event.issue.labels.*.name, 'A-Maths') || + contains(github.event.issue.labels.*.name, 'A-Location-Sharing') || + contains(github.event.issue.labels.*.name, 'Z-IA') || + contains(github.event.issue.labels.*.name, 'A-Jump-To-Date ') || + contains(github.event.issue.labels.*.name, 'A-Themes-Custom') || + contains(github.event.issue.labels.*.name, 'A-E2EE-Dehydration') || + contains(github.event.issue.labels.*.name, 'A-Tags') || + contains(github.event.issue.labels.*.name, 'A-Video-Rooms') || + contains(github.event.issue.labels.*.name, 'A-Message-Starring') || + contains(github.event.issue.labels.*.name, 'A-Rich-Text-Editor') || + contains(github.event.issue.labels.*.name, 'A-Element-Call') + steps: + - uses: actions/github-script@v7 + with: + script: | + github.rest.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: ['Z-Labs'] + }) + + apply_Help-Wanted_label: + name: Add "Help Wanted" label to all "good first issue" and Hacktoberfest + runs-on: ubuntu-24.04 + if: > + contains(github.event.issue.labels.*.name, 'good first issue') || + contains(github.event.issue.labels.*.name, 'Hacktoberfest') + steps: + - uses: actions/github-script@v7 + with: + script: | + github.rest.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: ['Help Wanted'] + }) + + move_needs_info_issues: + name: X-Needs-Info issues to Need info column on triage board + runs-on: ubuntu-24.04 + if: > + contains(github.event.issue.labels.*.name, 'X-Needs-Info') + steps: + - id: add_to_project + uses: actions/add-to-project@v1.0.2 + with: + project-url: ${{ env.PROJECT_URL }} + github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} + + - id: set_fields + uses: titoportas/update-project-fields@421a54430b3cdc9eefd8f14f9ce0142ab7678751 # v0.1.0 + with: + project-url: ${{ env.PROJECT_URL }} + github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} + item-id: ${{ steps.add_to_project.outputs.itemId }} # Use the item-id output of the previous step + field-keys: Status + field-values: "Needs info" + env: + PROJECT_URL: https://github.com/orgs/element-hq/projects/120 + + move_flakey_test_issues: + name: Z-Flaky-Test issues to Sized for maintainer column on triage board + runs-on: ubuntu-24.04 + if: > + contains(github.event.issue.labels.*.name, 'Z-Flaky-Test') + steps: + - id: add_to_project + uses: actions/add-to-project@v1.0.2 + with: + project-url: ${{ env.PROJECT_URL }} + github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} + + - id: set_fields + uses: titoportas/update-project-fields@421a54430b3cdc9eefd8f14f9ce0142ab7678751 # v0.1.0 + with: + project-url: ${{ env.PROJECT_URL }} + github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} + item-id: ${{ steps.add_to_project.outputs.itemId }} # Use the item-id output of the previous step + field-keys: Status + field-values: "Sized for maintainer" + env: + PROJECT_URL: https://github.com/orgs/element-hq/projects/120 + + add_priority_design_issues_to_project: + name: P1 X-Needs-Design to Design project board + runs-on: ubuntu-24.04 + if: > + contains(github.event.issue.labels.*.name, 'X-Needs-Design') && + (contains(github.event.issue.labels.*.name, 'S-Critical') && + (contains(github.event.issue.labels.*.name, 'O-Frequent') || + contains(github.event.issue.labels.*.name, 'O-Occasional')) || + contains(github.event.issue.labels.*.name, 'S-Major') && + contains(github.event.issue.labels.*.name, 'O-Frequent') || + contains(github.event.issue.labels.*.name, 'A11y')) + steps: + - uses: actions/add-to-project@main + with: + project-url: https://github.com/orgs/element-hq/projects/18 + github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} + + add_product_issues: + name: X-Needs-Product to product project board + runs-on: ubuntu-24.04 + if: > + contains(github.event.issue.labels.*.name, 'X-Needs-Product') + steps: + - uses: actions/add-to-project@main + with: + project-url: https://github.com/orgs/element-hq/projects/28 + github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} + + Search_issues_to_board: + name: Search issues to project board + runs-on: ubuntu-24.04 + if: > + contains(github.event.issue.labels.*.name, 'A-New-Search-Experience') + steps: + - uses: actions/add-to-project@main + with: + project-url: https://github.com/orgs/element-hq/projects/48 + github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} + + voip: + name: Add labelled issues to VoIP project board + runs-on: ubuntu-24.04 + if: > + contains(github.event.issue.labels.*.name, 'Team: VoIP') + steps: + - uses: actions/add-to-project@main + with: + project-url: https://github.com/orgs/element-hq/projects/41 + github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} + + verticals_feature: + name: Add labelled issues to Verticals Feature project + runs-on: ubuntu-24.04 + if: > + contains(github.event.issue.labels.*.name, 'Team: Verticals Feature') + steps: + - uses: actions/add-to-project@main + with: + project-url: https://github.com/orgs/element-hq/projects/57 + github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} + + tech_debt: + name: Add labelled issues to tech debt project + runs-on: ubuntu-24.04 + if: > + contains(github.event.issue.labels.*.name, 'A-Developer-Experience') || + contains(github.event.issue.labels.*.name, 'A-Documentation') || + contains(github.event.issue.labels.*.name, 'A-Packaging') || + contains(github.event.issue.labels.*.name, 'A-Technical-Debt') || + contains(github.event.issue.labels.*.name, 'A-Testing') || + contains(github.event.issue.labels.*.name, 'Z-Flaky-Test') + steps: + - uses: actions/add-to-project@main + with: + project-url: https://github.com/orgs/element-hq/projects/101 + github-token: ${{ secrets.ELEMENT_BOT_TOKEN }} diff --git a/.github/workflows/triage-move-review-requests.yml b/.github/workflows/triage-move-review-requests.yml new file mode 100644 index 00000000000..d3bcda270bb --- /dev/null +++ b/.github/workflows/triage-move-review-requests.yml @@ -0,0 +1,140 @@ +name: Move pull requests asking for review to the relevant project +on: + pull_request_target: + types: [review_requested] + +permissions: {} # Uses ELEMENT_BOT_TOKEN instead +jobs: + add_design_pr_to_project: + name: Move PRs asking for design review to the design board + runs-on: ubuntu-24.04 + steps: + - uses: octokit/graphql-action@v2.x + id: find_team_members + with: + headers: '{"GraphQL-Features": "projects_next_graphql"}' + query: | + query find_team_members($team: String!) { + organization(login: "element-hq") { + team(slug: $team) { + members { + nodes { + login + } + } + } + } + } + team: ${{ env.TEAM }} + env: + TEAM: "design" + GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} + - id: any_matching_reviewers + run: | + # Fetch requested reviewers, and people who are on the team + echo '${{ tojson(fromjson(steps.find_team_members.outputs.data).organization.team.members.nodes[*].login) }}' | tee /tmp/team_members.json + echo '${{ tojson(github.event.pull_request.requested_reviewers[*].login) }}' | tee /tmp/reviewers.json + jq --raw-output .[] < /tmp/team_members.json | sort | tee /tmp/team_members.txt + jq --raw-output .[] < /tmp/reviewers.json | sort | tee /tmp/reviewers.txt + + # Fetch requested team reviewers, and the name of the team + echo '${{ tojson(github.event.pull_request.requested_teams[*].slug) }}' | tee /tmp/team_reviewers.json + jq --raw-output .[] < /tmp/team_reviewers.json | sort | tee /tmp/team_reviewers.txt + echo '${{ env.TEAM }}' | tee /tmp/team.txt + + # If either a reviewer matches a team member, or a team matches our team, say "true" + if [ $(join /tmp/team_members.txt /tmp/reviewers.txt | wc -l) != 0 ]; then + echo "match=true" >> $GITHUB_OUTPUT + elif [ $(join /tmp/team.txt /tmp/team_reviewers.txt | wc -l) != 0 ]; then + echo "match=true" >> $GITHUB_OUTPUT + else + echo "match=false" >> $GITHUB_OUTPUT + fi + env: + TEAM: "design" + - uses: octokit/graphql-action@v2.x + id: add_to_project + if: steps.any_matching_reviewers.outputs.match == 'true' + with: + headers: '{"GraphQL-Features": "projects_next_graphql"}' + query: | + mutation add_to_project($projectid:ID!, $contentid:ID!) { + addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) { + item { + id + } + } + } + projectid: ${{ env.PROJECT_ID }} + contentid: ${{ github.event.pull_request.node_id }} + env: + PROJECT_ID: "PVT_kwDOAM0swc0sUA" + TEAM: "design" + GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} + + add_product_pr_to_project: + name: Move PRs asking for design review to the design board + runs-on: ubuntu-24.04 + steps: + - uses: octokit/graphql-action@v2.x + id: find_team_members + with: + headers: '{"GraphQL-Features": "projects_next_graphql"}' + query: | + query find_team_members($team: String!) { + organization(login: "element-hq") { + team(slug: $team) { + members { + nodes { + login + } + } + } + } + } + team: ${{ env.TEAM }} + env: + TEAM: "product" + GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} + - id: any_matching_reviewers + run: | + # Fetch requested reviewers, and people who are on the team + echo '${{ tojson(fromjson(steps.find_team_members.outputs.data).organization.team.members.nodes[*].login) }}' | tee /tmp/team_members.json + echo '${{ tojson(github.event.pull_request.requested_reviewers[*].login) }}' | tee /tmp/reviewers.json + jq --raw-output .[] < /tmp/team_members.json | sort | tee /tmp/team_members.txt + jq --raw-output .[] < /tmp/reviewers.json | sort | tee /tmp/reviewers.txt + + # Fetch requested team reviewers, and the name of the team + echo '${{ tojson(github.event.pull_request.requested_teams[*].slug) }}' | tee /tmp/team_reviewers.json + jq --raw-output .[] < /tmp/team_reviewers.json | sort | tee /tmp/team_reviewers.txt + echo '${{ env.TEAM }}' | tee /tmp/team.txt + + # If either a reviewer matches a team member, or a team matches our team, say "true" + if [ $(join /tmp/team_members.txt /tmp/reviewers.txt | wc -l) != 0 ]; then + echo "match=true" >> $GITHUB_OUTPUT + elif [ $(join /tmp/team.txt /tmp/team_reviewers.txt | wc -l) != 0 ]; then + echo "match=true" >> $GITHUB_OUTPUT + else + echo "match=false" >> $GITHUB_OUTPUT + fi + env: + TEAM: "product" + - uses: octokit/graphql-action@v2.x + id: add_to_project + if: steps.any_matching_reviewers.outputs.match == 'true' + with: + headers: '{"GraphQL-Features": "projects_next_graphql"}' + query: | + mutation add_to_project($projectid:ID!, $contentid:ID!) { + addProjectV2ItemById(input: {projectId: $projectid contentId: $contentid}) { + item { + id + } + } + } + projectid: ${{ env.PROJECT_ID }} + contentid: ${{ github.event.pull_request.node_id }} + env: + PROJECT_ID: "PVT_kwDOAM0swc4AAg6N" + TEAM: "product" + GITHUB_TOKEN: ${{ secrets.ELEMENT_BOT_TOKEN }} diff --git a/.github/workflows/triage-stale-flaky-tests.yml b/.github/workflows/triage-stale-flaky-tests.yml new file mode 100644 index 00000000000..90ba7c40f75 --- /dev/null +++ b/.github/workflows/triage-stale-flaky-tests.yml @@ -0,0 +1,19 @@ +name: Close stale flaky issues +on: + schedule: + - cron: "30 1 * * *" +permissions: {} +jobs: + close: + runs-on: ubuntu-24.04 + permissions: + actions: write + issues: write + steps: + - uses: actions/stale@v9 + with: + only-labels: "Z-Flaky-Test" + days-before-stale: 14 + days-before-close: 0 + close-issue-message: "This flaky test issue has not been updated in 14 days. It is being closed as presumed resolved." + exempt-issue-labels: "Z-Flaky-Test-Disabled" diff --git a/.github/workflows/triage-unlabelled.yml b/.github/workflows/triage-unlabelled.yml new file mode 100644 index 00000000000..efbf80eea99 --- /dev/null +++ b/.github/workflows/triage-unlabelled.yml @@ -0,0 +1,73 @@ +name: Move unlabelled from needs info columns to triaged + +on: + issues: + types: [unlabeled] +permissions: {} +jobs: + Move_Unabeled_Issue_On_Project_Board: + name: Move no longer X-Needs-Info issues to Triaged + runs-on: ubuntu-24.04 + permissions: + repository-projects: read + if: > + ${{ + !contains(github.event.issue.labels.*.name, 'X-Needs-Info') }} + env: + BOARD_NAME: "Issue triage" + OWNER: ${{ github.repository_owner }} + REPO: ${{ github.event.repository.name }} + ISSUE: ${{ github.event.issue.number }} + steps: + - name: Check if issue is already in "${{ env.BOARD_NAME }}" + run: | + json=$(curl -s -H 'Content-Type: application/json' -H "Authorization: bearer ${{ secrets.GITHUB_TOKEN }}" -X POST -d '{"query": "query($issue: Int!, $owner: String!, $repo: String!) { repository(owner: $owner, name: $repo) { issue(number: $issue) { projectCards { nodes { project { name } isArchived } } } } } ", "variables" : "{ \"issue\": '${ISSUE}', \"owner\": \"'${OWNER}'\", \"repo\": \"'${REPO}'\" }" }' https://api.github.com/graphql) + if echo $json | jq '.data.repository.issue.projectCards.nodes | length'; then + if [[ $(echo $json | jq '.data.repository.issue.projectCards.nodes[0].project.name') =~ "${BOARD_NAME}" ]]; then + if [[ $(echo $json | jq '.data.repository.issue.projectCards.nodes[0].isArchived') == 'true' ]]; then + echo "Issue is already in Project '$BOARD_NAME', but is archived - skipping workflow"; + echo "SKIP_ACTION=true" >> $GITHUB_ENV + else + echo "Issue is already in Project '$BOARD_NAME', proceeding"; + echo "ALREADY_IN_BOARD=true" >> $GITHUB_ENV + fi + else + echo "Issue is not in project '$BOARD_NAME', cancelling this workflow" + echo "ALREADY_IN_BOARD=false" >> $GITHUB_ENV + fi + fi + - name: Move issue + uses: alex-page/github-project-automation-plus@303f24a24c67ce7adf565a07e96720faf126fe36 + if: ${{ env.ALREADY_IN_BOARD == 'true' && env.SKIP_ACTION != 'true' }} + with: + project: Issue triage + column: Triaged + repo-token: ${{ secrets.ELEMENT_BOT_TOKEN }} + + remove_Z-Labs_label: + name: Remove Z-Labs label when features behind labs flags are removed + runs-on: ubuntu-24.04 + if: > + !(contains(github.event.issue.labels.*.name, 'A-Maths') || + contains(github.event.issue.labels.*.name, 'A-Message-Pinning') || + contains(github.event.issue.labels.*.name, 'A-Location-Sharing') || + contains(github.event.issue.labels.*.name, 'Z-IA') || + contains(github.event.issue.labels.*.name, 'A-Jump-To-Date') || + contains(github.event.issue.labels.*.name, 'A-Themes-Custom') || + contains(github.event.issue.labels.*.name, 'A-E2EE-Dehydration') || + contains(github.event.issue.labels.*.name, 'A-Tags') || + contains(github.event.issue.labels.*.name, 'A-Video-Rooms') || + contains(github.event.issue.labels.*.name, 'A-Message-Starring') || + contains(github.event.issue.labels.*.name, 'A-Rich-Text-Editor') || + contains(github.event.issue.labels.*.name, 'A-Element-Call')) && + contains(github.event.issue.labels.*.name, 'Z-Labs') + steps: + - uses: actions/github-script@v7 + with: + script: | + github.rest.issues.removeLabel({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + name: ['Z-Labs'] + }) diff --git a/.github/workflows/update-jitsi.yml b/.github/workflows/update-jitsi.yml new file mode 100644 index 00000000000..bf0414e73a4 --- /dev/null +++ b/.github/workflows/update-jitsi.yml @@ -0,0 +1,33 @@ +# Re-fetches the Jitsi SDK and opens a PR to update it if it's different from what's in the repository +name: Update Jitsi +on: + workflow_dispatch: {} + schedule: + - cron: "0 3 * * 0" # 3am every Sunday +permissions: {} # We use ELEMENT_BOT_TOKEN instead +jobs: + update: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-node@v4 + with: + cache: "yarn" + node-version: "lts/*" + + - name: Install Deps + run: "yarn install --frozen-lockfile" + + - name: Fetch Jitsi + run: "yarn update:jitsi" + + - name: Create Pull Request + uses: peter-evans/create-pull-request@5e914681df9dc83aa4e4905692ca88beb2f9e91f # v7 + with: + token: ${{ secrets.ELEMENT_BOT_TOKEN }} + branch: actions/jitsi-update + delete-branch: true + title: Jitsi Update + labels: | + T-Task diff --git a/.github/workflows/update-topics.yaml b/.github/workflows/update-topics.yaml new file mode 100644 index 00000000000..cd6c2fc5533 --- /dev/null +++ b/.github/workflows/update-topics.yaml @@ -0,0 +1,103 @@ +name: Update release topics +on: + workflow_dispatch: + inputs: + expected_status: + description: What type of release is the next expected release + required: true + default: RC + type: choice + options: + - RC + - Release + expected_date: + description: Expected release date e.g. July 11th + required: true + type: string +concurrency: ${{ github.workflow }} +permissions: {} # No permissions required +jobs: + bot: + name: Release topic update + runs-on: ubuntu-24.04 + environment: Matrix + steps: + - uses: actions/github-script@v7 + env: + HS_URL: ${{ secrets.BETABOT_HS_URL }} + LOBBY_ROOM_ID: ${{ secrets.ROOM_ID }} + PUBLIC_ROOM_ID: "!YTvKGNlinIzlkMTVRl:matrix.org" + ANNOUNCEMENT_ROOM_ID: "!bijaLdadorKgNGtHdA:matrix.org" + TOKEN: ${{ secrets.BETABOT_ACCESS_TOKEN }} + RELEASE_STATUS: "Release status: ${{ inputs.expected_status }} expected ${{ inputs.expected_date }}" + with: + script: | + const { HS_URL, TOKEN, RELEASE_STATUS, LOBBY_ROOM_ID, PUBLIC_ROOM_ID, ANNOUNCEMENT_ROOM_ID } = process.env; + + const repo = context.repo; + const { data } = await github.rest.repos.getLatestRelease({ + owner: repo.owner, + repo: repo.repo, + }); + console.log("Found latest version: " + data.tag_name); + + const releaseTopic = `Stable: ${data.tag_name} | ${RELEASE_STATUS}`; + console.log("Release topic: " + releaseTopic); + + const regex = /Stable: v(.+) \| Release status: (\w+) expected (\w+ \d+\w\w)/gm; + + async function updateReleaseInTopic(roomId) { + const apiUrl = `${HS_URL}/_matrix/client/v3/rooms/${roomId}/state/m.room.topic/`; + const headers = { + "Content-Type": "application/json", + "Authorization": `Bearer ${TOKEN}`, + }; + await fetch(`${HS_URL}/_matrix/client/v3/rooms/${roomId}/join`, { + method: "POST", + headers, + body: "{}", + }); + + let res = await fetch(apiUrl, { + method: "GET", + headers, + }); + + if (!res.ok) { + console.log(roomId, "failed to fetch", await res.text()); + return; + } + + const data = await res.json(); + console.log(roomId, "got event", data); + + const topic = data.topic.replace(regex, releaseTopic); + if (topic === data.topic) { + console.log(roomId, "nothing to do"); + return; + } + if (data["org.matrix.msc3765.topic"]) { + data["org.matrix.msc3765.topic"].forEach(d => { + d.body = d.body.replace(regex, releaseTopic); + }); + } + + res = await fetch(apiUrl, { + method: "PUT", + body: JSON.stringify({ + ...data, + topic, + }), + headers, + }); + + if (res.ok) { + console.log(roomId, "topic updated:", topic); + } else { + console.log(roomId, await res.text()); + } + } + + await updateReleaseInTopic(LOBBY_ROOM_ID); + await updateReleaseInTopic(PUBLIC_ROOM_ID); + await updateReleaseInTopic(ANNOUNCEMENT_ROOM_ID); diff --git a/.gitignore b/.gitignore index 5a140777f37..685a2cc3172 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,8 @@ package-lock.json electron/dist electron/pub **/.idea +/config.json +/config.json.* /config.local*.json # Legacy skinning file that some people might still have /src/component-index.js diff --git a/README.md b/README.md index 8ca08213ec1..fa4ac89ff99 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,313 @@ -[![Build](https://github.com/elecordapp/elecord-web/actions/workflows/build.yml/badge.svg)](https://github.com/elecordapp/elecord-web/actions/workflows/build.yml) +[![Chat](https://img.shields.io/matrix/element-web:matrix.org?logo=matrix)](https://matrix.to/#/#element-web:matrix.org) +![Tests](https://github.com/element-hq/element-web/actions/workflows/tests.yaml/badge.svg) +![Static Analysis](https://github.com/element-hq/element-web/actions/workflows/static_analysis.yaml/badge.svg) +[![Localazy](https://img.shields.io/endpoint?url=https%3A%2F%2Fconnect.localazy.com%2Fstatus%2Felement-web%2Fdata%3Fcontent%3Dall%26title%3Dlocalazy%26logo%3Dtrue)](https://localazy.com/p/element-web) +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=element-web&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=element-web) +[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=element-web&metric=coverage)](https://sonarcloud.io/summary/new_code?id=element-web) +[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=element-web&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=element-web) +[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=element-web&metric=bugs)](https://sonarcloud.io/summary/new_code?id=element-web) -# elecord-web +# Element - +Element (formerly known as Vector and Riot) is a Matrix web client built using the [Matrix +JS SDK](https://github.com/matrix-org/matrix-js-sdk). -#### Privacy focused chat app for gamers +# Supported Environments -Elecord is a heavily personalised fork of Element, a Matrix web client. +Element has several tiers of support for different environments: -For detailed documentation, see [element-web](https://github.com/element-hq/element-web). +- Supported + - Definition: + - Issues **actively triaged**, regressions **block** the release + - Last 2 major versions of Chrome, Firefox, and Edge on desktop OSes + - Last 2 versions of Safari + - Latest release of official Element Desktop app on desktop OSes + - Desktop OSes means macOS, Windows, and Linux versions for desktop devices + that are actively supported by the OS vendor and receive security updates +- Best effort + - Definition: + - Issues **accepted**, regressions **do not block** the release + - The wider Element Products(including Element Call and the Enterprise Server Suite) do still not officially support these browsers. + - The element web project and its contributors should keep the client functioning and gracefully degrade where other sibling features (E.g. Element Call) may not function. + - Last major release of Firefox ESR and Chrome/Edge Extended Stable +- Community Supported + - Definition: + - Issues **accepted**, regressions **do not block** the release + - Community contributions are welcome to support these issues + - Mobile web for current stable version of Chrome, Firefox, and Safari on Android, iOS, and iPadOS +- Not supported + - Definition: Issues only affecting unsupported environments are **closed** + - Everything else + +The period of support for these tiers should last until the releases specified above, plus 1 app release cycle(2 weeks). In the case of Firefox ESR this is extended further to allow it land in Debian Stable. + +For accessing Element on an Android or iOS device, we currently recommend the +native apps [element-android](https://github.com/element-hq/element-android) +and [element-ios](https://github.com/element-hq/element-ios). + +# Getting Started + +The easiest way to test Element is to just use the hosted copy at . +The `develop` branch is continuously deployed to +for those who like living dangerously. + +To host your own instance of Element see [Installing Element Web](docs/install.md). + +To install Element as a desktop application, see [Running as a desktop app](#running-as-a-desktop-app) below. + +# Important Security Notes + +## Separate domains + +We do not recommend running Element from the same domain name as your Matrix +homeserver. The reason is the risk of XSS (cross-site-scripting) +vulnerabilities that could occur if someone caused Element to load and render +malicious user generated content from a Matrix API which then had trusted +access to Element (or other apps) due to sharing the same domain. + +We have put some coarse mitigations into place to try to protect against this +situation, but it's still not good practice to do it in the first place. See + for more details. + +## Configuration best practices + +Unless you have special requirements, you will want to add the following to +your web server configuration when hosting Element Web: + +- The `X-Frame-Options: SAMEORIGIN` header, to prevent Element Web from being + framed and protect from [clickjacking][owasp-clickjacking]. +- The `frame-ancestors 'self'` directive to your `Content-Security-Policy` + header, as the modern replacement for `X-Frame-Options` (though both should be + included since not all browsers support it yet, see + [this][owasp-clickjacking-csp]). +- The `X-Content-Type-Options: nosniff` header, to [disable MIME + sniffing][mime-sniffing]. +- The `X-XSS-Protection: 1; mode=block;` header, for basic XSS protection in + legacy browsers. + +[mime-sniffing]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types#mime_sniffing +[owasp-clickjacking-csp]: https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html#content-security-policy-frame-ancestors-examples +[owasp-clickjacking]: https://cheatsheetseries.owasp.org/cheatsheets/Clickjacking_Defense_Cheat_Sheet.html + +If you are using nginx, this would look something like the following: + +``` +add_header X-Frame-Options SAMEORIGIN; +add_header X-Content-Type-Options nosniff; +add_header X-XSS-Protection "1; mode=block"; +add_header Content-Security-Policy "frame-ancestors 'self'"; +``` + +For Apache, the configuration looks like: + +``` +Header set X-Frame-Options SAMEORIGIN +Header set X-Content-Type-Options nosniff +Header set X-XSS-Protection "1; mode=block" +Header set Content-Security-Policy "frame-ancestors 'self'" +``` + +Note: In case you are already setting a `Content-Security-Policy` header +elsewhere, you should modify it to include the `frame-ancestors` directive +instead of adding that last line. + +# Building From Source + +Element is a modular webapp built with modern ES6 and uses a Node.js build system. +Ensure you have the latest LTS version of Node.js installed. + +Using `yarn` instead of `npm` is recommended. Please see the Yarn [install +guide](https://classic.yarnpkg.com/en/docs/install) if you do not have it already. + +1. Install or update `node.js` so that your `node` is at least the current recommended LTS. +1. Install `yarn` if not present already. +1. Clone the repo: `git clone https://github.com/element-hq/element-web.git`. +1. Switch to the element-web directory: `cd element-web`. +1. Install the prerequisites: `yarn install`. + - If you're using the `develop` branch, then it is recommended to set up a + proper development environment (see [Setting up a dev + environment](#setting-up-a-dev-environment) below). Alternatively, you + can use - the continuous integration release of + the develop branch. +1. Configure the app by copying `config.sample.json` to `config.json` and + modifying it. See the [configuration docs](docs/config.md) for details. +1. `yarn dist` to build a tarball to deploy. Untaring this file will give + a version-specific directory containing all the files that need to go on your + web server. + +Note that `yarn dist` is not supported on Windows, so Windows users can run `yarn build`, +which will build all the necessary files into the `webapp` directory. The version of Element +will not appear in Settings without using the dist script. You can then mount the +`webapp` directory on your web server to actually serve up the app, which is +entirely static content. + +# Running as a Desktop app + +Element can also be run as a desktop app, wrapped in Electron. You can download a +pre-built version from or, if you prefer, +build it yourself. + +To build it yourself, follow the instructions at . + +Many thanks to @aviraldg for the initial work on the Electron integration. + +The [configuration docs](docs/config.md#desktop-app-configuration) show how to override the desktop app's default settings if desired. + +# config.json + +Element supports a variety of settings to configure default servers, behaviour, themes, etc. +See the [configuration docs](docs/config.md) for more details. + +# Labs Features + +Some features of Element may be enabled by flags in the `Labs` section of the settings. +Some of these features are described in [labs.md](https://github.com/element-hq/element-web/blob/develop/docs/labs.md). + +# Caching requirements + +Element requires the following URLs not to be cached, when/if you are serving Element from your own webserver: + +``` +/config.*.json +/i18n +/home +/sites +/index.html +``` + +We also recommend that you force browsers to re-validate any cached copy of Element on page load by configuring your +webserver to return `Cache-Control: no-cache` for `/`. This ensures the browser will fetch a new version of Element on +the next page load after it's been deployed. Note that this is already configured for you in the nginx config of our +Dockerfile. + +# Development + +Before attempting to develop on Element you **must** read the [developer guide +for `matrix-react-sdk`](https://github.com/matrix-org/matrix-react-sdk#developer-guide), which +also defines the design, architecture and style for Element too. + +Read the [Choosing an issue](docs/choosing-an-issue.md) page for some guidance +about where to start. Before starting work on a feature, it's best to ensure +your plan aligns well with our vision for Element. Please chat with the team in +[#element-dev:matrix.org](https://matrix.to/#/#element-dev:matrix.org) before +you start so we can ensure it's something we'd be willing to merge. + +You should also familiarise yourself with the ["Here be Dragons" guide +](https://docs.google.com/document/d/12jYzvkidrp1h7liEuLIe6BMdU0NUjndUYI971O06ooM) +to the tame & not-so-tame dragons (gotchas) which exist in the codebase. + +The idea of Element is to be a relatively lightweight "skin" of customisations on +top of the underlying `matrix-react-sdk`. `matrix-react-sdk` provides both the +higher and lower level React components useful for building Matrix communication +apps using React. + +Please note that Element is intended to run correctly without access to the public +internet. So please don't depend on resources (JS libs, CSS, images, fonts) +hosted by external CDNs or servers but instead please package all dependencies +into Element itself. + +# Setting up a dev environment + +Much of the functionality in Element is actually in the `matrix-js-sdk` module. +It is possible to set these up in a way that makes it easy to track the `develop` branches +in git and to make local changes without having to manually rebuild each time. + +First clone and build `matrix-js-sdk`: + +```bash +git clone https://github.com/matrix-org/matrix-js-sdk.git +pushd matrix-js-sdk +yarn link +yarn install +popd +``` + +Clone the repo and switch to the `element-web` directory: + +```bash +git clone https://github.com/element-hq/element-web.git +cd element-web +``` + +Configure the app by copying `config.sample.json` to `config.json` and +modifying it. See the [configuration docs](docs/config.md) for details. + +Finally, build and start Element itself: + +```bash +yarn link matrix-js-sdk +yarn install +yarn start +``` + +Wait a few seconds for the initial build to finish; you should see something like: + +``` +[element-js] [webpack.Progress] 100% +[element-js] +[element-js] ℹ 「wdm」: 1840 modules +[element-js] ℹ 「wdm」: Compiled successfully. +``` + +Remember, the command will not terminate since it runs the web server +and rebuilds source files when they change. This development server also +disables caching, so do NOT use it in production. + +Open in your browser to see your newly built Element. + +**Note**: The build script uses inotify by default on Linux to monitor directories +for changes. If the inotify limits are too low your build will fail silently or with +`Error: EMFILE: too many open files`. To avoid these issues, we recommend a watch limit +of at least `128M` and instance limit around `512`. + +You may be interested in issues [#15750](https://github.com/element-hq/element-web/issues/15750) and +[#15774](https://github.com/element-hq/element-web/issues/15774) for further details. + +To set a new inotify watch and instance limit, execute: + +``` +sudo sysctl fs.inotify.max_user_watches=131072 +sudo sysctl fs.inotify.max_user_instances=512 +sudo sysctl -p +``` + +If you wish, you can make the new limits permanent, by executing: + +``` +echo fs.inotify.max_user_watches=131072 | sudo tee -a /etc/sysctl.conf +echo fs.inotify.max_user_instances=512 | sudo tee -a /etc/sysctl.conf +sudo sysctl -p +``` + +--- + +When you make changes to `matrix-js-sdk` they should be automatically picked up by webpack and built. + +If any of these steps error with, `file table overflow`, you are probably on a mac +which has a very low limit on max open files. Run `ulimit -Sn 1024` and try again. +You'll need to do this in each new terminal you open before building Element. + +## Running the tests + +There are a number of application-level tests in the `tests` directory; these +are designed to run with Jest and JSDOM. To run them + +``` +yarn test +``` + +### End-to-End tests + +See [matrix-react-sdk](https://github.com/matrix-org/matrix-react-sdk/#end-to-end-tests) for how to run the end-to-end tests. + +# Translations + +To add a new translation, head to the [translating doc](docs/translating.md). + +For a developer guide, see the [translating dev doc](docs/translating-dev.md). + +# Triaging issues + +Issues are triaged by community members and the Web App Team, following the [triage process](https://github.com/element-hq/element-meta/wiki/Triage-process). + +We use [issue labels](https://github.com/element-hq/element-meta/wiki/Issue-labelling) to sort all incoming issues. diff --git a/banner.webp b/banner.webp deleted file mode 100644 index 6747255e133..00000000000 Binary files a/banner.webp and /dev/null differ diff --git a/config.json b/config.json deleted file mode 100644 index f26c0613f0b..00000000000 --- a/config.json +++ /dev/null @@ -1,53 +0,0 @@ -{ - "default_server_name": "matrix.org", - "default_server_config": { - "m.homeserver": { - "base_url": "https://matrix-client.matrix.org" - }, - "m.identity_server": { - "base_url": "https://vector.im" - } - }, - "brand": "elecord", - "integrations_ui_url": "https://scalar.vector.im/", - "integrations_rest_url": "https://scalar.vector.im/api", - "integrations_widgets_urls": [ - "https://scalar.vector.im/_matrix/integrations/v1", - "https://scalar.vector.im/api", - "https://scalar-staging.vector.im/_matrix/integrations/v1", - "https://scalar-staging.vector.im/api", - "https://scalar-staging.riot.im/scalar/api" - ], - "bug_report_endpoint_url": "https://element.io/bugreports/submit", - "uisi_autorageshake_app": "element-auto-uisi", - "show_labs_settings": false, - "room_directory": { - "servers": ["matrix.org", "gitter.im"] - }, - "enable_presence_by_hs_url": { - "https://matrix.org": false, - "https://matrix-client.matrix.org": false - }, - "terms_and_conditions_links": [ - { - "url": "https://element.io/privacy", - "text": "Privacy Policy" - }, - { - "url": "https://element.io/cookie-policy", - "text": "Cookie Policy" - } - ], - "privacy_policy_url": "https://element.io/cookie-policy", - "setting_defaults": { - "RustCrypto.staged_rollout_percent": 100 - }, - "features": { - "feature_video_rooms": true, - "feature_group_calls": true, - "feature_element_call_video_rooms": true - }, - "element_call": { - "url": "https://call.element.io" - } -} \ No newline at end of file diff --git a/res/manifest.json b/res/manifest.json index 69f8ecf86b4..f6f1e91bf47 100644 --- a/res/manifest.json +++ b/res/manifest.json @@ -1,8 +1,8 @@ { - "name": "elecord", - "short_name": "elecord", + "name": "Element", + "short_name": "Element", "display": "standalone", - "theme_color": "#3e9fed", + "theme_color": "#76CFA6", "start_url": "index.html", "icons": [ { diff --git a/res/themes/element/img/backgrounds/lake.jpg b/res/themes/element/img/backgrounds/lake.jpg index f824133faa1..eb3d19a7cc9 100644 Binary files a/res/themes/element/img/backgrounds/lake.jpg and b/res/themes/element/img/backgrounds/lake.jpg differ diff --git a/res/themes/element/img/logos/element-logo.svg b/res/themes/element/img/logos/element-logo.svg index 540a6081d7e..54a91b72f80 100644 --- a/res/themes/element/img/logos/element-logo.svg +++ b/res/themes/element/img/logos/element-logo.svg @@ -1,124 +1,7 @@ - - - - + + + + + + + diff --git a/res/themes/element/img/logos/opengraph.png b/res/themes/element/img/logos/opengraph.png index d818fdd7242..d1b9d70e081 100644 Binary files a/res/themes/element/img/logos/opengraph.png and b/res/themes/element/img/logos/opengraph.png differ diff --git a/res/vector-icons/1024.png b/res/vector-icons/1024.png index 3e301e8b288..f4f073930b3 100644 Binary files a/res/vector-icons/1024.png and b/res/vector-icons/1024.png differ diff --git a/res/vector-icons/120.png b/res/vector-icons/120.png index 067192ef63b..5a8544944e5 100644 Binary files a/res/vector-icons/120.png and b/res/vector-icons/120.png differ diff --git a/res/vector-icons/1240x600.png b/res/vector-icons/1240x600.png index c2fff2de00e..11a963db656 100644 Binary files a/res/vector-icons/1240x600.png and b/res/vector-icons/1240x600.png differ diff --git a/res/vector-icons/150.png b/res/vector-icons/150.png index 4a5755ff091..407668e679f 100644 Binary files a/res/vector-icons/150.png and b/res/vector-icons/150.png differ diff --git a/res/vector-icons/152.png b/res/vector-icons/152.png index 7002fb34f3b..aefe0df014d 100644 Binary files a/res/vector-icons/152.png and b/res/vector-icons/152.png differ diff --git a/res/vector-icons/180.png b/res/vector-icons/180.png index 1934189ef0e..bfb7a33243f 100644 Binary files a/res/vector-icons/180.png and b/res/vector-icons/180.png differ diff --git a/res/vector-icons/24.png b/res/vector-icons/24.png index a3bf9914bbb..b0ef723eb8f 100644 Binary files a/res/vector-icons/24.png and b/res/vector-icons/24.png differ diff --git a/res/vector-icons/300.png b/res/vector-icons/300.png index d28397dda1f..6cbb21a5689 100644 Binary files a/res/vector-icons/300.png and b/res/vector-icons/300.png differ diff --git a/res/vector-icons/44.png b/res/vector-icons/44.png index c4e7dd58775..171508dde03 100644 Binary files a/res/vector-icons/44.png and b/res/vector-icons/44.png differ diff --git a/res/vector-icons/50.png b/res/vector-icons/50.png index b2da2aa85fe..1d8de2bf06d 100644 Binary files a/res/vector-icons/50.png and b/res/vector-icons/50.png differ diff --git a/res/vector-icons/620x300.png b/res/vector-icons/620x300.png index 0b6c8ad08d0..f05c32b1c91 100644 Binary files a/res/vector-icons/620x300.png and b/res/vector-icons/620x300.png differ diff --git a/res/vector-icons/76.png b/res/vector-icons/76.png index d9a21d55dd3..05af3bb8dd2 100644 Binary files a/res/vector-icons/76.png and b/res/vector-icons/76.png differ diff --git a/res/vector-icons/88.png b/res/vector-icons/88.png index 3268223ff2a..dec953bcf58 100644 Binary files a/res/vector-icons/88.png and b/res/vector-icons/88.png differ diff --git a/res/vector-icons/apple-touch-icon-114.png b/res/vector-icons/apple-touch-icon-114.png index c1be161ee3b..1ae39a6debf 100644 Binary files a/res/vector-icons/apple-touch-icon-114.png and b/res/vector-icons/apple-touch-icon-114.png differ diff --git a/res/vector-icons/apple-touch-icon-120.png b/res/vector-icons/apple-touch-icon-120.png index 067192ef63b..749f941a1e1 100644 Binary files a/res/vector-icons/apple-touch-icon-120.png and b/res/vector-icons/apple-touch-icon-120.png differ diff --git a/res/vector-icons/apple-touch-icon-144.png b/res/vector-icons/apple-touch-icon-144.png index 0a5981f7a92..0dcc56a8027 100644 Binary files a/res/vector-icons/apple-touch-icon-144.png and b/res/vector-icons/apple-touch-icon-144.png differ diff --git a/res/vector-icons/apple-touch-icon-152.png b/res/vector-icons/apple-touch-icon-152.png index 7002fb34f3b..2ac8c6dce44 100644 Binary files a/res/vector-icons/apple-touch-icon-152.png and b/res/vector-icons/apple-touch-icon-152.png differ diff --git a/res/vector-icons/apple-touch-icon-180.png b/res/vector-icons/apple-touch-icon-180.png index 1934189ef0e..f87d72db939 100644 Binary files a/res/vector-icons/apple-touch-icon-180.png and b/res/vector-icons/apple-touch-icon-180.png differ diff --git a/res/vector-icons/apple-touch-icon-57.png b/res/vector-icons/apple-touch-icon-57.png index 6fef2668e52..d80f3859548 100644 Binary files a/res/vector-icons/apple-touch-icon-57.png and b/res/vector-icons/apple-touch-icon-57.png differ diff --git a/res/vector-icons/apple-touch-icon-60.png b/res/vector-icons/apple-touch-icon-60.png index c25a535613f..d5ec84b0382 100644 Binary files a/res/vector-icons/apple-touch-icon-60.png and b/res/vector-icons/apple-touch-icon-60.png differ diff --git a/res/vector-icons/apple-touch-icon-72.png b/res/vector-icons/apple-touch-icon-72.png index 25ab6435528..85dbe1b82f4 100644 Binary files a/res/vector-icons/apple-touch-icon-72.png and b/res/vector-icons/apple-touch-icon-72.png differ diff --git a/res/vector-icons/apple-touch-icon-76.png b/res/vector-icons/apple-touch-icon-76.png index d9a21d55dd3..f328d1bd612 100644 Binary files a/res/vector-icons/apple-touch-icon-76.png and b/res/vector-icons/apple-touch-icon-76.png differ diff --git a/res/vector-icons/favicon.ico b/res/vector-icons/favicon.ico index 72d09f14292..6ad5fb08651 100644 Binary files a/res/vector-icons/favicon.ico and b/res/vector-icons/favicon.ico differ diff --git a/res/vector-icons/mstile-150.png b/res/vector-icons/mstile-150.png index 4a5755ff091..6606d425f29 100644 Binary files a/res/vector-icons/mstile-150.png and b/res/vector-icons/mstile-150.png differ diff --git a/res/vector-icons/mstile-310.png b/res/vector-icons/mstile-310.png index d1ef0938ff2..0ce998223b3 100644 Binary files a/res/vector-icons/mstile-310.png and b/res/vector-icons/mstile-310.png differ diff --git a/res/vector-icons/mstile-310x150.png b/res/vector-icons/mstile-310x150.png index 16a53e2ae9d..42efd6a98e1 100644 Binary files a/res/vector-icons/mstile-310x150.png and b/res/vector-icons/mstile-310x150.png differ diff --git a/res/vector-icons/mstile-70.png b/res/vector-icons/mstile-70.png index ce677aec418..709056bc61a 100644 Binary files a/res/vector-icons/mstile-70.png and b/res/vector-icons/mstile-70.png differ diff --git a/scripts/ci_package.sh b/scripts/ci_package.sh index 87ccd4fe1f6..d5736420c35 100755 --- a/scripts/ci_package.sh +++ b/scripts/ci_package.sh @@ -4,7 +4,7 @@ set -ex -rm dist/elecord-*.tar.gz || true # rm previous artifacts without failing if it doesn't exist +rm dist/element-*.tar.gz || true # rm previous artifacts without failing if it doesn't exist DIST_VERSION=`$(dirname $0)/get-version-from-git.sh` diff --git a/scripts/package.sh b/scripts/package.sh index 590771dadc0..9937dd20d3b 100755 --- a/scripts/package.sh +++ b/scripts/package.sh @@ -15,19 +15,16 @@ VERSION=$version yarn build # `yarn build`, but it's just too painful. cp config.sample.json webapp/ -# Copy any required files for deployment -cp .github/cfp_headers webapp/_headers - mkdir -p dist -cp -r webapp elecord-$version +cp -r webapp element-$version # Just in case you have a local config, remove it before packaging -# rm elecord-$version/config.json || true +rm element-$version/config.json || true # GNU/BSD compatibility workaround tar_perms=(--owner=0 --group=0) && [ "$(uname)" == "Darwin" ] && tar_perms=(--uid=0 --gid=0) -tar "${tar_perms[@]}" -chvzf dist/elecord-$version.tar.gz elecord-$version -rm -r elecord-$version +tar "${tar_perms[@]}" -chvzf dist/element-$version.tar.gz element-$version +rm -r element-$version echo -echo "Packaged dist/elecord-$version.tar.gz" +echo "Packaged dist/element-$version.tar.gz" diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index f2ad5ce7ac2..66428300a08 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -645,7 +645,7 @@ "stop_voice_message": "Stop recording", "voice_message_button": "Voice Message" }, - "console_dev_note": "If you know what you're doing, elecord is open-source, be sure to check out our GitHub (https://github.com/elecordapp/elecord-web/) and contribute!", + "console_dev_note": "If you know what you're doing, Element is open-source, be sure to check out our GitHub (https://github.com/vector-im/element-web/) and contribute!", "console_scam_warning": "If someone told you to copy/paste something here, there is a high likelihood you're being scammed!", "console_wait": "Wait!", "create_room": { @@ -1039,11 +1039,11 @@ "hs_blocked": "This homeserver has been blocked by its administrator.", "invalid_configuration_mixed_server": "Invalid configuration: a default_hs_url can't be specified along with default_server_name or default_server_config", "invalid_configuration_no_server": "Invalid configuration: no default server specified.", - "invalid_json": "Your elecord configuration contains invalid JSON. Please correct the problem and reload the page.", + "invalid_json": "Your Element configuration contains invalid JSON. Please correct the problem and reload the page.", "invalid_json_detail": "The message from the parser is: %(message)s", "invalid_json_generic": "Invalid JSON", "mau": "This homeserver has hit its Monthly Active User limit.", - "misconfigured": "Your elecord is misconfigured", + "misconfigured": "Your Element is misconfigured", "mixed_content": "Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. Either use HTTPS or enable unsafe scripts.", "non_urgent_echo_failure_toast": "Your server isn't responding to some requests.", "resource_limits": "This homeserver has exceeded one of its resource limits.", @@ -3978,7 +3978,7 @@ "you_are_presenting": "You are presenting" }, "web_default_device_name": "%(appName)s: %(browserName)s on %(osName)s", - "welcome_to_element": "Welcome to elecord", + "welcome_to_element": "Welcome to Element", "widget": { "added_by": "Widget added by", "capabilities_dialog": { diff --git a/src/vector/index.html b/src/vector/index.html index a2b80a61324..0c21a0791b6 100644 --- a/src/vector/index.html +++ b/src/vector/index.html @@ -2,7 +2,7 @@ - elecord + Element @@ -16,13 +16,13 @@ - - + + - - + + - +
<%