add nudge related translations to desktop and web message files (#14905) #41450
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This workflow will run in the context of the source of the PR. | |
# On a PR from a fork, the workflow will not have access to secrets, and so any parts of the build that require secrets will not run. | |
# If additional artifacts are needed, the failed "build-web-target.yml" workflow held up by the check-run should be re-run. | |
name: Build Web | |
on: | |
pull_request: | |
types: [opened, synchronize] | |
branches-ignore: | |
- 'l10n_master' | |
- 'cf-pages' | |
paths: | |
- 'apps/web/**' | |
- 'bitwarden_license/bit-common/**' | |
- 'bitwarden_license/bit-web/**' | |
- 'libs/**' | |
- '*' | |
- '!*.md' | |
- '!*.txt' | |
- '.github/workflows/build-web.yml' | |
push: | |
branches: | |
- 'main' | |
- 'rc' | |
- 'hotfix-rc-web' | |
paths: | |
- 'apps/web/**' | |
- 'bitwarden_license/bit-common/**' | |
- 'bitwarden_license/bit-web/**' | |
- 'libs/**' | |
- '*' | |
- '!*.md' | |
- '!*.txt' | |
- '.github/workflows/build-web.yml' | |
release: | |
types: [published] | |
workflow_call: | |
inputs: {} | |
workflow_dispatch: | |
inputs: | |
custom_tag_extension: | |
description: "Custom image tag extension" | |
required: false | |
sdk_branch: | |
description: "Custom SDK branch" | |
required: false | |
type: string | |
env: | |
_AZ_REGISTRY: bitwardenprod.azurecr.io | |
_GITHUB_PR_REPO_NAME: ${{ github.event.pull_request.head.repo.full_name }} | |
jobs: | |
setup: | |
name: Setup | |
runs-on: ubuntu-24.04 | |
outputs: | |
version: ${{ steps.version.outputs.value }} | |
node_version: ${{ steps.retrieve-node-version.outputs.node_version }} | |
has_secrets: ${{ steps.check-secrets.outputs.has_secrets }} | |
steps: | |
- name: Check out repo | |
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
with: | |
ref: ${{ github.event.pull_request.head.sha }} | |
- name: Get GitHub sha as version | |
id: version | |
run: echo "value=${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT | |
- name: Get Node Version | |
id: retrieve-node-version | |
run: | | |
NODE_NVMRC=$(cat .nvmrc) | |
NODE_VERSION=${NODE_NVMRC/v/''} | |
echo "node_version=$NODE_VERSION" >> $GITHUB_OUTPUT | |
- name: Check secrets | |
id: check-secrets | |
env: | |
AZURE_KV_CI_SERVICE_PRINCIPAL: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} | |
run: | | |
has_secrets=${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL != '' }} | |
echo "has_secrets=$has_secrets" >> $GITHUB_OUTPUT | |
build-containers: | |
name: "Build [${{matrix.artifact_name}}], image tag: [${{matrix.image_name}}]" | |
runs-on: ubuntu-24.04 | |
permissions: | |
security-events: write | |
id-token: write | |
needs: setup | |
strategy: | |
fail-fast: false | |
matrix: | |
include: | |
- artifact_name: selfhosted-open-source | |
image_name: web-oss | |
npm_command: dist:oss:selfhost | |
- artifact_name: cloud-COMMERCIAL | |
image_name: web-cloud | |
npm_command: dist:bit:cloud | |
- artifact_name: selfhosted-COMMERCIAL | |
image_name: web | |
npm_command: dist:bit:selfhost | |
- artifact_name: cloud-QA | |
image_name: web-qa-cloud | |
npm_command: build:bit:qa | |
git_metadata: true | |
- artifact_name: ee | |
image_name: web-ee | |
npm_command: build:bit:ee | |
git_metadata: true | |
- artifact_name: cloud-euprd | |
image_name: web-euprd | |
npm_command: build:bit:euprd | |
- artifact_name: cloud-euqa | |
image_name: web-euqa | |
npm_command: build:bit:euqa | |
git_metadata: true | |
- artifact_name: cloud-usdev | |
image_name: web-usdev | |
npm_command: build:bit:usdev | |
git_metadata: true | |
env: | |
_NODE_VERSION: ${{ needs.setup.outputs.node_version }} | |
_VERSION: ${{ needs.setup.outputs.version }} | |
steps: | |
- name: Check out repo | |
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
with: | |
ref: ${{ github.event.pull_request.head.sha }} | |
- name: Get Latest Server Version | |
id: latest-server-version | |
uses: bitwarden/gh-actions/get-release-version@main | |
with: | |
repository: bitwarden/server | |
trim: false | |
- name: Set Server Ref | |
id: set-server-ref | |
run: | | |
SERVER_REF="${{ steps.latest-server-version.outputs.version }}" | |
echo "Latest server release version: $SERVER_REF" | |
if [[ "$GITHUB_REF" == "refs/heads/main" ]]; then | |
SERVER_REF="$GITHUB_REF" | |
elif [[ "$GITHUB_REF" == "refs/heads/rc" ]]; then | |
SERVER_REF="$GITHUB_REF" | |
elif [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then | |
SERVER_REF="refs/heads/main" | |
fi | |
echo "Server ref: $SERVER_REF" | |
echo "server_ref=$SERVER_REF" >> $GITHUB_OUTPUT | |
- name: Check out Server repo | |
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
with: | |
path: server | |
repository: bitwarden/server | |
ref: ${{ steps.set-server-ref.outputs.server_ref }} | |
- name: Check Branch to Publish | |
env: | |
PUBLISH_BRANCHES: "main,rc,hotfix-rc-web" | |
id: publish-branch-check | |
run: | | |
IFS="," read -a publish_branches <<< $PUBLISH_BRANCHES | |
if [[ " ${publish_branches[*]} " =~ " ${GITHUB_REF:11} " ]]; then | |
echo "is_publish_branch=true" >> $GITHUB_ENV | |
else | |
echo "is_publish_branch=false" >> $GITHUB_ENV | |
fi | |
- name: Add Git metadata to build version | |
working-directory: apps/web | |
if: matrix.git_metadata | |
run: | | |
VERSION=$( jq -r ".version" package.json) | |
jq --arg version "$VERSION+${GITHUB_SHA:0:7}" '.version = $version' package.json > package.json.tmp | |
mv package.json.tmp package.json | |
########## Set up Docker ########## | |
- name: Set up Docker | |
uses: docker/setup-docker-action@b60f85385d03ac8acfca6d9996982511d8620a19 # v4.3.0 | |
with: | |
daemon-config: | | |
{ | |
"debug": true, | |
"features": { | |
"containerd-snapshotter": true | |
} | |
} | |
- name: Set up QEMU emulators | |
uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 # v3.6.0 | |
- name: Set up Docker Buildx | |
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 | |
########## ACRs ########## | |
- name: Login to Prod Azure | |
if: ${{ needs.setup.outputs.has_secrets == 'true' }} | |
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 | |
with: | |
creds: ${{ secrets.AZURE_PROD_KV_CREDENTIALS }} | |
- name: Log into Prod container registry | |
if: ${{ needs.setup.outputs.has_secrets == 'true' }} | |
run: az acr login -n ${_AZ_REGISTRY%.azurecr.io} | |
########## Generate image tag and build Docker image ########## | |
- name: Generate container image tag | |
id: tag | |
run: | | |
if [[ "${GITHUB_EVENT_NAME}" == "pull_request" || "${GITHUB_EVENT_NAME}" == "pull_request_target" ]]; then | |
IMAGE_TAG=$(echo "${GITHUB_HEAD_REF}" | sed "s/[^a-zA-Z0-9]/-/g") # Sanitize branch name to alphanumeric only | |
else | |
IMAGE_TAG=$(echo "${GITHUB_REF_NAME}" | sed "s#/#-#g") | |
fi | |
if [[ "${{ github.event.pull_request.head.repo.fork }}" == "true" ]]; then | |
SANITIZED_REPO_NAME=$(echo "$_GITHUB_PR_REPO_NAME" | sed "s/[^a-zA-Z0-9]/-/g") # Sanitize repo name to alphanumeric only | |
IMAGE_TAG=$SANITIZED_REPO_NAME-$IMAGE_TAG # Add repo name to the tag | |
IMAGE_TAG=${IMAGE_TAG:0:128} # Limit to 128 characters, as that's the max length for Docker image tags | |
fi | |
if [[ "$IMAGE_TAG" == "main" ]]; then | |
IMAGE_TAG=dev | |
fi | |
TAG_EXTENSION=${{ github.event.inputs.custom_tag_extension }} | |
if [[ $TAG_EXTENSION ]]; then | |
IMAGE_TAG=$IMAGE_TAG-$TAG_EXTENSION | |
fi | |
echo "image_tag=$IMAGE_TAG" >> $GITHUB_OUTPUT | |
########## Build Image ########## | |
- name: Generate image full name | |
id: image-name | |
env: | |
IMAGE_TAG: ${{ steps.tag.outputs.image_tag }} | |
PROJECT_NAME: ${{ matrix.image_name }} | |
run: echo "name=$_AZ_REGISTRY/${PROJECT_NAME}:${IMAGE_TAG}" >> $GITHUB_OUTPUT | |
- name: Build Docker image | |
id: build-container | |
uses: docker/build-push-action@67a2d409c0a876cbe6b11854e3e25193efe4e62d # v6.12.0 | |
with: | |
build-args: | | |
NODE_VERSION=${{ env._NODE_VERSION }} | |
NPM_COMMAND=${{ matrix.npm_command }} | |
context: . | |
file: apps/web/Dockerfile | |
load: true | |
platforms: | | |
linux/amd64, | |
linux/arm/v7, | |
linux/arm64 | |
push: false | |
tags: ${{ steps.image-name.outputs.name }} | |
- name: Push images | |
if: ${{ needs.setup.outputs.has_secrets == 'true' }} | |
env: | |
IMAGE_NAME: ${{ steps.image-name.outputs.name }} | |
run: docker push $IMAGE_NAME | |
- name: Zip project | |
working-directory: apps/web | |
env: | |
IMAGE_NAME: ${{ steps.image-name.outputs.name }} | |
run: | | |
mkdir build | |
docker run --rm --volume $(pwd)/build:/temp --entrypoint bash \ | |
$IMAGE_NAME -c "cp -r ./ /temp" | |
zip -r web-${{ env._VERSION }}-${{ matrix.artifact_name }}.zip build | |
- name: Upload ${{ matrix.artifact_name }} artifact | |
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 | |
with: | |
name: web-${{ env._VERSION }}-${{ matrix.artifact_name }}.zip | |
path: apps/web/web-${{ env._VERSION }}-${{ matrix.artifact_name }}.zip | |
if-no-files-found: error | |
- name: Install Cosign | |
if: github.event_name != 'pull_request_target' && github.ref == 'refs/heads/main' | |
uses: sigstore/cosign-installer@3454372f43399081ed03b604cb2d021dabca52bb # v3.8.2 | |
- name: Sign image with Cosign | |
if: github.event_name != 'pull_request_target' && github.ref == 'refs/heads/main' | |
env: | |
DIGEST: ${{ steps.build-container.outputs.digest }} | |
TAGS: ${{ steps.image-name.outputs.name }} | |
run: | | |
IFS="," read -a tags <<< "${TAGS}" | |
images="" | |
for tag in "${tags[@]}"; do | |
images+="${tag}@${DIGEST} " | |
done | |
cosign sign --yes ${images} | |
- name: Scan Docker image | |
if: ${{ needs.setup.outputs.has_secrets == 'true' }} | |
id: container-scan | |
uses: anchore/scan-action@869c549e657a088dc0441b08ce4fc0ecdac2bb65 # v5.3.0 | |
with: | |
image: ${{ steps.image-name.outputs.name }} | |
fail-build: false | |
output-format: sarif | |
- name: Upload Grype results to GitHub | |
if: ${{ needs.setup.outputs.has_secrets == 'true' }} | |
uses: github/codeql-action/upload-sarif@d68b2d4edb4189fd2a5366ac14e72027bd4b37dd # v3.28.2 | |
with: | |
sarif_file: ${{ steps.container-scan.outputs.sarif }} | |
sha: ${{ contains(github.event_name, 'pull_request') && github.event.pull_request.head.sha || github.sha }} | |
ref: ${{ contains(github.event_name, 'pull_request') && format('refs/pull/{0}/head', github.event.pull_request.number) || github.ref }} | |
- name: Log out of Docker | |
run: docker logout $_AZ_REGISTRY | |
crowdin-push: | |
name: Crowdin Push | |
if: github.event_name != 'pull_request_target' && github.ref == 'refs/heads/main' | |
needs: build-containers | |
runs-on: ubuntu-24.04 | |
steps: | |
- name: Check out repo | |
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 | |
with: | |
ref: ${{ github.event.pull_request.head.sha }} | |
- name: Login to Azure | |
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 | |
with: | |
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} | |
- name: Retrieve secrets | |
id: retrieve-secrets | |
uses: bitwarden/gh-actions/get-keyvault-secrets@main | |
with: | |
keyvault: "bitwarden-ci" | |
secrets: "crowdin-api-token" | |
- name: Upload Sources | |
uses: crowdin/github-action@30849777a3cba6ee9a09e24e195272b8287a0a5b # v1.20.4 | |
env: | |
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
CROWDIN_API_TOKEN: ${{ steps.retrieve-secrets.outputs.crowdin-api-token }} | |
CROWDIN_PROJECT_ID: "308189" | |
with: | |
config: apps/web/crowdin.yml | |
crowdin_branch_name: main | |
upload_sources: true | |
upload_translations: false | |
trigger-web-vault-deploy: | |
name: Trigger web vault deploy | |
if: github.event_name != 'pull_request_target' && github.ref == 'refs/heads/main' | |
runs-on: ubuntu-24.04 | |
needs: build-containers | |
steps: | |
- name: Login to Azure - CI Subscription | |
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 | |
with: | |
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} | |
- name: Retrieve github PAT secrets | |
id: retrieve-secret-pat | |
uses: bitwarden/gh-actions/get-keyvault-secrets@main | |
with: | |
keyvault: "bitwarden-ci" | |
secrets: "github-pat-bitwarden-devops-bot-repo-scope" | |
- name: Trigger web vault deploy using GitHub Run ID | |
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 | |
with: | |
github-token: ${{ steps.retrieve-secret-pat.outputs.github-pat-bitwarden-devops-bot-repo-scope }} | |
script: | | |
await github.rest.actions.createWorkflowDispatch({ | |
owner: 'bitwarden', | |
repo: 'clients', | |
workflow_id: 'deploy-web.yml', | |
ref: 'main', | |
inputs: { | |
'environment': 'USDEV', | |
'build-web-run-id': '${{ github.run_id }}' | |
} | |
}) | |
check-failures: | |
name: Check for failures | |
if: always() | |
runs-on: ubuntu-24.04 | |
needs: | |
- setup | |
- build-containers | |
- crowdin-push | |
- trigger-web-vault-deploy | |
steps: | |
- name: Check if any job failed | |
if: | | |
github.event_name != 'pull_request_target' | |
&& (github.ref == 'refs/heads/main' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc-web') | |
&& contains(needs.*.result, 'failure') | |
run: exit 1 | |
- name: Login to Azure - Prod Subscription | |
uses: Azure/login@e15b166166a8746d1a47596803bd8c1b595455cf # v1.6.0 | |
if: failure() | |
with: | |
creds: ${{ secrets.AZURE_KV_CI_SERVICE_PRINCIPAL }} | |
- name: Retrieve secrets | |
id: retrieve-secrets | |
if: failure() | |
uses: bitwarden/gh-actions/get-keyvault-secrets@main | |
with: | |
keyvault: "bitwarden-ci" | |
secrets: "devops-alerts-slack-webhook-url" | |
- name: Notify Slack on failure | |
uses: act10ns/slack@44541246747a30eb3102d87f7a4cc5471b0ffb7d # v2.1.0 | |
if: failure() | |
env: | |
SLACK_WEBHOOK_URL: ${{ steps.retrieve-secrets.outputs.devops-alerts-slack-webhook-url }} | |
with: | |
status: ${{ job.status }} |