mirror of
https://github.com/bitwarden/browser
synced 2026-02-02 17:53:41 +00:00
Merge remote-tracking branch 'refs/remotes/origin/dirt/pm-23680/new-report-applications' into dirt/pm-23680/new-report-applications
This commit is contained in:
2
.github/CODEOWNERS
vendored
2
.github/CODEOWNERS
vendored
@@ -180,6 +180,8 @@ libs/common/src/key-management @bitwarden/team-key-management-dev
|
||||
libs/node @bitwarden/team-key-management-dev
|
||||
|
||||
apps/desktop/desktop_native/core/src/biometric/ @bitwarden/team-key-management-dev
|
||||
apps/desktop/desktop_native/core/src/biometric_v2/ @bitwarden/team-key-management-dev
|
||||
apps/desktop/desktop_native/core/src/secure_memory/ @bitwarden/team-key-management-dev
|
||||
apps/desktop/src/services/native-messaging.service.ts @bitwarden/team-key-management-dev
|
||||
apps/browser/src/background/nativeMessaging.background.ts @bitwarden/team-key-management-dev
|
||||
apps/desktop/src/services/biometric-message-handler.service.ts @bitwarden/team-key-management-dev
|
||||
|
||||
@@ -17,6 +17,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Get changed files
|
||||
id: changed-files
|
||||
@@ -68,9 +69,11 @@ jobs:
|
||||
- name: Comment on PR if monitored files changed
|
||||
if: steps.changed-files.outputs.monitored == 'true'
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
||||
env:
|
||||
_MONITORED_FILES: ${{ steps.changed-files.outputs.monitored_files }}
|
||||
with:
|
||||
script: |
|
||||
const changedFiles = `${{ steps.changed-files.outputs.monitored_files }}`.split(' ').filter(file => file.trim() !== '');
|
||||
const changedFiles = `$_MONITORED_FILES`.split(' ').filter(file => file.trim() !== '');
|
||||
|
||||
const message = `<!-- comment_tag: ddg-test-warning -->
|
||||
⚠️🦆 **DuckDuckGo Integration files have been modified in this PR:**
|
||||
|
||||
11
.github/workflows/auto-branch-updater.yml
vendored
11
.github/workflows/auto-branch-updater.yml
vendored
@@ -27,17 +27,20 @@ jobs:
|
||||
steps:
|
||||
- name: Setup
|
||||
id: setup
|
||||
run: echo "branch=${GITHUB_REF#refs/heads/}" >> $GITHUB_OUTPUT
|
||||
run: echo "branch=${GITHUB_REF#refs/heads/}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: 'eu-web-${{ steps.setup.outputs.branch }}'
|
||||
fetch-depth: 0
|
||||
persist-credentials: true
|
||||
|
||||
- name: Merge ${{ steps.setup.outputs.branch }}
|
||||
env:
|
||||
_BRANCH: ${{ steps.setup.outputs.branch }}
|
||||
run: |
|
||||
git config --local user.email "${{ env._BOT_EMAIL }}"
|
||||
git config --local user.name "${{ env._BOT_NAME }}"
|
||||
git merge origin/${{ steps.setup.outputs.branch }}
|
||||
git config --local user.email "$_BOT_EMAIL"
|
||||
git config --local user.name "$_BOT_NAME"
|
||||
git merge "origin/$_BRANCH"
|
||||
git push
|
||||
|
||||
62
.github/workflows/build-browser.yml
vendored
62
.github/workflows/build-browser.yml
vendored
@@ -58,15 +58,16 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Get Package Version
|
||||
id: gen_vars
|
||||
run: |
|
||||
repo_url=https://github.com/$GITHUB_REPOSITORY.git
|
||||
repo_url="https://github.com/$GITHUB_REPOSITORY.git"
|
||||
adj_build_num=${GITHUB_SHA:0:7}
|
||||
|
||||
echo "repo_url=$repo_url" >> $GITHUB_OUTPUT
|
||||
echo "adj_build_number=$adj_build_num" >> $GITHUB_OUTPUT
|
||||
echo "repo_url=$repo_url" >> "$GITHUB_OUTPUT"
|
||||
echo "adj_build_number=$adj_build_num" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Get Node Version
|
||||
id: retrieve-node-version
|
||||
@@ -74,13 +75,13 @@ jobs:
|
||||
run: |
|
||||
NODE_NVMRC=$(cat .nvmrc)
|
||||
NODE_VERSION=${NODE_NVMRC/v/''}
|
||||
echo "node_version=$NODE_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "node_version=$NODE_VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Check secrets
|
||||
id: check-secrets
|
||||
run: |
|
||||
has_secrets=${{ secrets.AZURE_CLIENT_ID != '' }}
|
||||
echo "has_secrets=$has_secrets" >> $GITHUB_OUTPUT
|
||||
echo "has_secrets=$has_secrets" >> "$GITHUB_OUTPUT"
|
||||
|
||||
|
||||
locales-test:
|
||||
@@ -96,6 +97,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Testing locales - extName length
|
||||
run: |
|
||||
@@ -105,12 +107,14 @@ jobs:
|
||||
echo "============"
|
||||
echo "extName string must be 40 characters or less"
|
||||
echo
|
||||
for locale in $(ls src/_locales/); do
|
||||
string_length=$(jq '.extName.message | length' src/_locales/$locale/messages.json)
|
||||
if [[ $string_length -gt 40 ]]; then
|
||||
echo "$locale: $string_length"
|
||||
found_error=true
|
||||
fi
|
||||
|
||||
for locale_path in src/_locales/*/messages.json; do
|
||||
locale=$(basename "$(dirname "$locale_path")")
|
||||
string_length=$(jq '.extName.message | length' "$locale_path")
|
||||
if [ "$string_length" -gt 40 ]; then
|
||||
echo "$locale: $string_length"
|
||||
found_error=true
|
||||
fi
|
||||
done
|
||||
|
||||
if $found_error; then
|
||||
@@ -145,6 +149,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
@@ -246,6 +251,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
@@ -301,13 +307,13 @@ jobs:
|
||||
TARGET_DIR='./browser-source/apps/browser'
|
||||
while IFS=' ' read -r RESULT; do
|
||||
FILES+=("$RESULT")
|
||||
done < <(find $TARGET_DIR -size +5M)
|
||||
done < <(find "$TARGET_DIR" -size +5M)
|
||||
|
||||
# Validate results and provide messaging
|
||||
if [[ ${#FILES[@]} -ne 0 ]]; then
|
||||
echo "File(s) exceeds size limit: 5MB"
|
||||
for FILE in ${FILES[@]}; do
|
||||
echo "- $(du --si $FILE)"
|
||||
for FILE in "${FILES[@]}"; do
|
||||
echo "- $(du --si "$FILE")"
|
||||
done
|
||||
echo "ERROR Firefox rejects extension uploads that contain files larger than 5MB"
|
||||
# Invoke failure
|
||||
@@ -357,6 +363,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
@@ -389,34 +396,34 @@ jobs:
|
||||
ACCOUNT_NAME: bitwardenci
|
||||
CONTAINER_NAME: profiles
|
||||
run: |
|
||||
mkdir -p $HOME/secrets
|
||||
mkdir -p "$HOME/secrets"
|
||||
|
||||
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
|
||||
az storage blob download --account-name "$ACCOUNT_NAME" --container-name "$CONTAINER_NAME" \
|
||||
--name bitwarden_desktop_appstore.provisionprofile \
|
||||
--file $HOME/secrets/bitwarden_desktop_appstore.provisionprofile \
|
||||
--file "$HOME/secrets/bitwarden_desktop_appstore.provisionprofile" \
|
||||
--output none
|
||||
|
||||
- name: Get certificates
|
||||
run: |
|
||||
mkdir -p $HOME/certificates
|
||||
mkdir -p "$HOME/certificates"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/bitwarden-desktop-key |
|
||||
jq -r .value | base64 -d > $HOME/certificates/bitwarden-desktop-key.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/bitwarden-desktop-key.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/appstore-app-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/appstore-app-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/appstore-app-cert.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/appstore-installer-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/appstore-installer-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/appstore-installer-cert.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-app-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/devid-app-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/devid-app-cert.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-installer-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/devid-installer-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/devid-installer-cert.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/macdev-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/macdev-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/macdev-cert.p12"
|
||||
|
||||
- name: Log out from Azure
|
||||
uses: bitwarden/gh-actions/azure-logout@main
|
||||
@@ -425,9 +432,9 @@ jobs:
|
||||
env:
|
||||
KEYCHAIN_PASSWORD: ${{ steps.get-kv-secrets.outputs.KEYCHAIN-PASSWORD }}
|
||||
run: |
|
||||
security create-keychain -p $KEYCHAIN_PASSWORD build.keychain
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
security default-keychain -s build.keychain
|
||||
security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
security set-keychain-settings -lut 1200 build.keychain
|
||||
|
||||
security import "$HOME/certificates/bitwarden-desktop-key.p12" -k build.keychain -P "" \
|
||||
@@ -448,7 +455,7 @@ jobs:
|
||||
security import "$HOME/certificates/macdev-cert.p12" -k build.keychain -P "" \
|
||||
-T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild
|
||||
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain
|
||||
|
||||
- name: NPM setup
|
||||
run: npm ci
|
||||
@@ -507,6 +514,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Log in to Azure
|
||||
uses: bitwarden/gh-actions/azure-login@main
|
||||
|
||||
76
.github/workflows/build-cli.yml
vendored
76
.github/workflows/build-cli.yml
vendored
@@ -62,26 +62,27 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Get Package Version
|
||||
id: retrieve-package-version
|
||||
run: |
|
||||
PKG_VERSION=$(jq -r .version package.json)
|
||||
echo "package_version=$PKG_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "package_version=$PKG_VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Get Node Version
|
||||
id: retrieve-node-version
|
||||
working-directory: ./
|
||||
run: |
|
||||
NODE_NVMRC=$(cat .nvmrc)
|
||||
NODE_VERSION=${NODE_NVMRC/v/''}
|
||||
echo "node_version=$NODE_VERSION" >> $GITHUB_OUTPUT
|
||||
NODE_VERSION="${NODE_NVMRC/v/''}"
|
||||
echo "node_version=$NODE_VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Check secrets
|
||||
id: check-secrets
|
||||
run: |
|
||||
has_secrets=${{ secrets.AZURE_CLIENT_ID != '' }}
|
||||
echo "has_secrets=$has_secrets" >> $GITHUB_OUTPUT
|
||||
echo "has_secrets=$has_secrets" >> "$GITHUB_OUTPUT"
|
||||
|
||||
|
||||
cli:
|
||||
@@ -116,12 +117,17 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Unix Vars
|
||||
run: |
|
||||
echo "LOWER_RUNNER_OS=$(echo $RUNNER_OS | awk '{print tolower($0)}')" >> $GITHUB_ENV
|
||||
echo "SHORT_RUNNER_OS=$(echo $RUNNER_OS | awk '{print substr($0, 1, 3)}' | \
|
||||
awk '{print tolower($0)}')" >> $GITHUB_ENV
|
||||
LOWER_RUNNER_OS="$(printf '%s' "$RUNNER_OS" | awk '{print tolower($0)}')"
|
||||
SHORT_RUNNER_OS="$(printf '%s' "$RUNNER_OS" | awk '{print substr($0, 1, 3)}' | awk '{print tolower($0)}')"
|
||||
|
||||
{
|
||||
echo "LOWER_RUNNER_OS=$LOWER_RUNNER_OS"
|
||||
echo "SHORT_RUNNER_OS=$SHORT_RUNNER_OS"
|
||||
} >> "$GITHUB_ENV"
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
@@ -155,7 +161,9 @@ jobs:
|
||||
npm link ../sdk-internal
|
||||
|
||||
- name: Build & Package Unix
|
||||
run: npm run dist:${{ matrix.license_type.build_prefix }}:${{ env.SHORT_RUNNER_OS }}${{ matrix.os.target_suffix }} --quiet
|
||||
env:
|
||||
_SHORT_RUNNER_OS: ${{ env.SHORT_RUNNER_OS }}
|
||||
run: npm run "dist:${{ matrix.license_type.build_prefix }}:$_SHORT_RUNNER_OS${{ matrix.os.target_suffix }}" --quiet
|
||||
|
||||
- name: Login to Azure
|
||||
if: ${{ matrix.os.base == 'mac' && needs.setup.outputs.has_secrets == 'true' }}
|
||||
@@ -168,10 +176,10 @@ jobs:
|
||||
- name: Get certificates
|
||||
if: ${{ matrix.os.base == 'mac' && needs.setup.outputs.has_secrets == 'true' }}
|
||||
run: |
|
||||
mkdir -p $HOME/certificates
|
||||
mkdir -p "$HOME/certificates"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-app-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/devid-app-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/devid-app-cert.p12"
|
||||
|
||||
- name: Get Azure Key Vault secrets
|
||||
id: get-kv-secrets
|
||||
@@ -189,33 +197,39 @@ jobs:
|
||||
env:
|
||||
KEYCHAIN_PASSWORD: ${{ steps.get-kv-secrets.outputs.KEYCHAIN-PASSWORD }}
|
||||
run: |
|
||||
security create-keychain -p $KEYCHAIN_PASSWORD build.keychain
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
security default-keychain -s build.keychain
|
||||
security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
security set-keychain-settings -lut 1200 build.keychain
|
||||
|
||||
security import "$HOME/certificates/devid-app-cert.p12" -k build.keychain -P "" \
|
||||
-T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild
|
||||
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain
|
||||
|
||||
- name: Sign binary
|
||||
if: ${{ matrix.os.base == 'mac' && needs.setup.outputs.has_secrets == 'true' }}
|
||||
env:
|
||||
MACOS_CERTIFICATE_NAME: "Developer ID Application: 8bit Solutions LLC"
|
||||
run: codesign --sign "$MACOS_CERTIFICATE_NAME" --verbose=3 --force --options=runtime --entitlements ./entitlements.plist --timestamp ./dist/${{ matrix.license_type.build_prefix }}/${{ env.LOWER_RUNNER_OS }}${{ matrix.os.target_suffix }}/bw
|
||||
_LOWER_RUNNER_OS: ${{ env.LOWER_RUNNER_OS }}
|
||||
run: codesign --sign "$MACOS_CERTIFICATE_NAME" --verbose=3 --force --options=runtime --entitlements ./entitlements.plist --timestamp "./dist/${{ matrix.license_type.build_prefix }}/$_LOWER_RUNNER_OS${{ matrix.os.target_suffix }}/bw"
|
||||
|
||||
- name: Zip Unix
|
||||
env:
|
||||
_LOWER_RUNNER_OS: ${{ env.LOWER_RUNNER_OS }}
|
||||
_PACKAGE_VERSION: ${{ env._PACKAGE_VERSION }}
|
||||
run: |
|
||||
cd ./dist/${{ matrix.license_type.build_prefix }}/${{ env.LOWER_RUNNER_OS }}${{ matrix.os.target_suffix }}
|
||||
zip ../../bw${{ matrix.license_type.artifact_prefix }}-${{ env.LOWER_RUNNER_OS }}${{ matrix.os.target_suffix }}-${{ env._PACKAGE_VERSION }}.zip ./bw
|
||||
cd "./dist/${{ matrix.license_type.build_prefix }}/$_LOWER_RUNNER_OS${{ matrix.os.target_suffix }}"
|
||||
zip "../../bw${{ matrix.license_type.artifact_prefix }}-$_LOWER_RUNNER_OS${{ matrix.os.target_suffix }}-$_PACKAGE_VERSION.zip" ./bw
|
||||
|
||||
- name: Set up private auth key
|
||||
if: ${{ matrix.os.base == 'mac' && needs.setup.outputs.has_secrets == 'true' }}
|
||||
env:
|
||||
_APP_STORE_CONNECT_AUTH_KEY: ${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-AUTH-KEY }}
|
||||
run: |
|
||||
mkdir ~/private_keys
|
||||
cat << EOF > ~/private_keys/AuthKey_6TV9MKN3GP.p8
|
||||
${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-AUTH-KEY }}
|
||||
$_APP_STORE_CONNECT_AUTH_KEY
|
||||
EOF
|
||||
|
||||
- name: Notarize app
|
||||
@@ -224,22 +238,26 @@ jobs:
|
||||
APP_STORE_CONNECT_TEAM_ISSUER: ${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-TEAM-ISSUER }}
|
||||
APP_STORE_CONNECT_AUTH_KEY: 6TV9MKN3GP
|
||||
APP_STORE_CONNECT_AUTH_KEY_PATH: ~/private_keys/AuthKey_6TV9MKN3GP.p8
|
||||
_LOWER_RUNNER_OS: ${{ env.LOWER_RUNNER_OS }}
|
||||
run: |
|
||||
echo "Create keychain profile"
|
||||
xcrun notarytool store-credentials "notarytool-profile" --key-id "$APP_STORE_CONNECT_AUTH_KEY" --key "$APP_STORE_CONNECT_AUTH_KEY_PATH" --issuer "$APP_STORE_CONNECT_TEAM_ISSUER"
|
||||
|
||||
codesign --sign "Developer ID Application: 8bit Solutions LLC" --verbose=3 --force --options=runtime --timestamp ./dist/bw${{ matrix.license_type.artifact_prefix }}-${{ env.LOWER_RUNNER_OS }}${{ matrix.os.target_suffix }}-${{ env._PACKAGE_VERSION }}.zip
|
||||
codesign --sign "Developer ID Application: 8bit Solutions LLC" --verbose=3 --force --options=runtime --timestamp "./dist/bw${{ matrix.license_type.artifact_prefix }}-$_LOWER_RUNNER_OS${{ matrix.os.target_suffix }}-$_PACKAGE_VERSION.zip"
|
||||
|
||||
echo "Notarize app"
|
||||
xcrun notarytool submit ./dist/bw${{ matrix.license_type.artifact_prefix }}-${{ env.LOWER_RUNNER_OS }}${{ matrix.os.target_suffix }}-${{ env._PACKAGE_VERSION }}.zip --keychain-profile "notarytool-profile" --wait
|
||||
xcrun notarytool submit "./dist/bw${{ matrix.license_type.artifact_prefix }}-$_LOWER_RUNNER_OS${{ matrix.os.target_suffix }}-$_PACKAGE_VERSION.zip" --keychain-profile "notarytool-profile" --wait
|
||||
|
||||
- name: Version Test
|
||||
env:
|
||||
_PACKAGE_VERSION: ${{ env._PACKAGE_VERSION }}
|
||||
_LOWER_RUNNER_OS: ${{ env.LOWER_RUNNER_OS }}
|
||||
run: |
|
||||
unzip "./dist/bw${{ matrix.license_type.artifact_prefix }}-${{ env.LOWER_RUNNER_OS }}${{ matrix.os.target_suffix }}-${{ env._PACKAGE_VERSION }}.zip" -d "./test"
|
||||
unzip "./dist/bw${{ matrix.license_type.artifact_prefix }}-$_LOWER_RUNNER_OS${{ matrix.os.target_suffix }}-$_PACKAGE_VERSION.zip" -d "./test"
|
||||
testVersion=$(./test/bw -v)
|
||||
echo "version: $_PACKAGE_VERSION"
|
||||
echo "testVersion: $testVersion"
|
||||
if [[ $testVersion != $_PACKAGE_VERSION ]]; then
|
||||
if [[ $testVersion != "$_PACKAGE_VERSION" ]]; then
|
||||
echo "Version test failed."
|
||||
exit 1
|
||||
fi
|
||||
@@ -291,6 +309,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install AST
|
||||
run: dotnet tool install --global AzureSignTool --version 4.0.1
|
||||
@@ -429,11 +448,13 @@ jobs:
|
||||
- name: Package Chocolatey
|
||||
shell: pwsh
|
||||
if: ${{ matrix.license_type.build_prefix == 'bit' }}
|
||||
env:
|
||||
_PACKAGE_VERSION: ${{ env._PACKAGE_VERSION }}
|
||||
run: |
|
||||
Copy-Item -Path stores/chocolatey -Destination dist/chocolatey -Recurse
|
||||
Copy-Item dist/${{ matrix.license_type.build_prefix }}/windows/bw.exe -Destination dist/chocolatey/tools
|
||||
Copy-Item ${{ github.workspace }}/LICENSE.txt -Destination dist/chocolatey/tools
|
||||
choco pack dist/chocolatey/bitwarden-cli.nuspec --version ${{ env._PACKAGE_VERSION }} --out dist/chocolatey
|
||||
choco pack dist/chocolatey/bitwarden-cli.nuspec --version "$env:_PACKAGE_VERSION" --out dist/chocolatey
|
||||
|
||||
- name: Zip Windows
|
||||
shell: cmd
|
||||
@@ -466,7 +487,9 @@ jobs:
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Zip NPM Build Artifact
|
||||
run: Get-ChildItem -Path .\build | Compress-Archive -DestinationPath .\bitwarden-cli-${{ env._PACKAGE_VERSION }}-npm-build.zip
|
||||
env:
|
||||
_PACKAGE_VERSION: ${{ env._PACKAGE_VERSION }}
|
||||
run: Get-ChildItem -Path .\build | Compress-Archive -DestinationPath ".\bitwarden-cli-${env:_PACKAGE_VERSION}-npm-build.zip"
|
||||
|
||||
- name: Upload NPM Build Directory asset
|
||||
if: matrix.license_type.build_prefix == 'bit'
|
||||
@@ -490,8 +513,11 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Print environment
|
||||
env:
|
||||
_PACKAGE_VERSION: ${{ env._PACKAGE_VERSION }}
|
||||
run: |
|
||||
whoami
|
||||
echo "GitHub ref: $GITHUB_REF"
|
||||
@@ -505,9 +531,11 @@ jobs:
|
||||
path: apps/cli/dist/snap
|
||||
|
||||
- name: Setup Snap Package
|
||||
env:
|
||||
_PACKAGE_VERSION: ${{ env._PACKAGE_VERSION }}
|
||||
run: |
|
||||
cp -r stores/snap/* -t dist/snap
|
||||
sed -i s/__version__/${{ env._PACKAGE_VERSION }}/g dist/snap/snapcraft.yaml
|
||||
sed -i "s/__version__/$_PACKAGE_VERSION/g" "dist/snap/snapcraft.yaml"
|
||||
cd dist/snap
|
||||
ls -alth
|
||||
|
||||
|
||||
243
.github/workflows/build-desktop.yml
vendored
243
.github/workflows/build-desktop.yml
vendored
@@ -58,6 +58,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Verify
|
||||
run: |
|
||||
@@ -90,35 +91,38 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: true
|
||||
|
||||
- name: Get Package Version
|
||||
id: retrieve-version
|
||||
run: |
|
||||
PKG_VERSION=$(jq -r .version src/package.json)
|
||||
echo "Setting version number to $PKG_VERSION"
|
||||
echo "package_version=$PKG_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "package_version=$PKG_VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Increment Version
|
||||
id: increment-version
|
||||
run: |
|
||||
BUILD_NUMBER=$(expr 3000 + $GITHUB_RUN_NUMBER)
|
||||
BUILD_NUMBER=$((3000 + GITHUB_RUN_NUMBER))
|
||||
echo "Setting build number to $BUILD_NUMBER"
|
||||
echo "build_number=$BUILD_NUMBER" >> $GITHUB_OUTPUT
|
||||
echo "build_number=$BUILD_NUMBER" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Get Version Channel
|
||||
id: release-channel
|
||||
env:
|
||||
_PACKAGE_VERSION: ${{ steps.retrieve-version.outputs.package_version }}
|
||||
run: |
|
||||
case "${{ steps.retrieve-version.outputs.package_version }}" in
|
||||
case "$_PACKAGE_VERSION" in
|
||||
*"alpha"*)
|
||||
echo "channel=alpha" >> $GITHUB_OUTPUT
|
||||
echo "channel=alpha" >> "$GITHUB_OUTPUT"
|
||||
echo "[!] We do not yet support 'alpha'"
|
||||
exit 1
|
||||
;;
|
||||
*"beta"*)
|
||||
echo "channel=beta" >> $GITHUB_OUTPUT
|
||||
echo "channel=beta" >> "$GITHUB_OUTPUT"
|
||||
;;
|
||||
*)
|
||||
echo "channel=latest" >> $GITHUB_OUTPUT
|
||||
echo "channel=latest" >> "$GITHUB_OUTPUT"
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -126,15 +130,15 @@ jobs:
|
||||
id: branch-check
|
||||
run: |
|
||||
if [[ $(git ls-remote --heads origin rc) ]]; then
|
||||
echo "rc_branch_exists=1" >> $GITHUB_OUTPUT
|
||||
echo "rc_branch_exists=1" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "rc_branch_exists=0" >> $GITHUB_OUTPUT
|
||||
echo "rc_branch_exists=0" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
if [[ $(git ls-remote --heads origin hotfix-rc-desktop) ]]; then
|
||||
echo "hotfix_branch_exists=1" >> $GITHUB_OUTPUT
|
||||
echo "hotfix_branch_exists=1" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "hotfix_branch_exists=0" >> $GITHUB_OUTPUT
|
||||
echo "hotfix_branch_exists=0" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Get Node Version
|
||||
@@ -143,13 +147,13 @@ jobs:
|
||||
run: |
|
||||
NODE_NVMRC=$(cat .nvmrc)
|
||||
NODE_VERSION=${NODE_NVMRC/v/''}
|
||||
echo "node_version=$NODE_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "node_version=$NODE_VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Check secrets
|
||||
id: check-secrets
|
||||
run: |
|
||||
has_secrets=${{ secrets.AZURE_CLIENT_ID != '' }}
|
||||
echo "has_secrets=$has_secrets" >> $GITHUB_OUTPUT
|
||||
echo "has_secrets=$has_secrets" >> "$GITHUB_OUTPUT"
|
||||
|
||||
linux:
|
||||
name: Linux Build
|
||||
@@ -172,6 +176,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
@@ -321,6 +326,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
@@ -427,6 +433,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
@@ -533,21 +540,21 @@ jobs:
|
||||
- name: Rename appx files for store
|
||||
if: ${{ needs.setup.outputs.has_secrets == 'true' }}
|
||||
run: |
|
||||
Copy-Item "./dist/Bitwarden-${{ env._PACKAGE_VERSION }}-ia32.appx" `
|
||||
-Destination "./dist/Bitwarden-${{ env._PACKAGE_VERSION }}-ia32-store.appx"
|
||||
Copy-Item "./dist/Bitwarden-${{ env._PACKAGE_VERSION }}-x64.appx" `
|
||||
-Destination "./dist/Bitwarden-${{ env._PACKAGE_VERSION }}-x64-store.appx"
|
||||
Copy-Item "./dist/Bitwarden-${{ env._PACKAGE_VERSION }}-arm64.appx" `
|
||||
-Destination "./dist/Bitwarden-${{ env._PACKAGE_VERSION }}-arm64-store.appx"
|
||||
Copy-Item "./dist/Bitwarden-$env:_PACKAGE_VERSION-ia32.appx" `
|
||||
-Destination "./dist/Bitwarden-$env:_PACKAGE_VERSION-ia32-store.appx"
|
||||
Copy-Item "./dist/Bitwarden-$env:_PACKAGE_VERSION-x64.appx" `
|
||||
-Destination "./dist/Bitwarden-$env:_PACKAGE_VERSION-x64-store.appx"
|
||||
Copy-Item "./dist/Bitwarden-$env:_PACKAGE_VERSION-arm64.appx" `
|
||||
-Destination "./dist/Bitwarden-$env:_PACKAGE_VERSION-arm64-store.appx"
|
||||
|
||||
- name: Package for Chocolatey
|
||||
if: ${{ needs.setup.outputs.has_secrets == 'true' }}
|
||||
run: |
|
||||
Copy-Item -Path ./stores/chocolatey -Destination ./dist/chocolatey -Recurse
|
||||
Copy-Item -Path ./dist/nsis-web/Bitwarden-Installer-${{ env._PACKAGE_VERSION }}.exe `
|
||||
Copy-Item -Path ./dist/nsis-web/Bitwarden-Installer-$env:_PACKAGE_VERSION.exe `
|
||||
-Destination ./dist/chocolatey
|
||||
|
||||
$checksum = checksum -t sha256 ./dist/chocolatey/Bitwarden-Installer-${{ env._PACKAGE_VERSION }}.exe
|
||||
$checksum = checksum -t sha256 ./dist/chocolatey/Bitwarden-Installer-$env:_PACKAGE_VERSION.exe
|
||||
$chocoInstall = "./dist/chocolatey/tools/chocolateyinstall.ps1"
|
||||
(Get-Content $chocoInstall).replace('__version__', "$env:_PACKAGE_VERSION").replace('__checksum__', $checksum) | Set-Content $chocoInstall
|
||||
choco pack ./dist/chocolatey/bitwarden.nuspec --version "$env:_PACKAGE_VERSION" --out ./dist/chocolatey
|
||||
@@ -555,12 +562,12 @@ jobs:
|
||||
- name: Fix NSIS artifact names for auto-updater
|
||||
if: ${{ needs.setup.outputs.has_secrets == 'true' }}
|
||||
run: |
|
||||
Rename-Item -Path .\dist\nsis-web\Bitwarden-${{ env._PACKAGE_VERSION }}-ia32.nsis.7z `
|
||||
-NewName bitwarden-${{ env._PACKAGE_VERSION }}-ia32.nsis.7z
|
||||
Rename-Item -Path .\dist\nsis-web\Bitwarden-${{ env._PACKAGE_VERSION }}-x64.nsis.7z `
|
||||
-NewName bitwarden-${{ env._PACKAGE_VERSION }}-x64.nsis.7z
|
||||
Rename-Item -Path .\dist\nsis-web\Bitwarden-${{ env._PACKAGE_VERSION }}-arm64.nsis.7z `
|
||||
-NewName bitwarden-${{ env._PACKAGE_VERSION }}-arm64.nsis.7z
|
||||
Rename-Item -Path .\dist\nsis-web\Bitwarden-$env:_PACKAGE_VERSION-ia32.nsis.7z `
|
||||
-NewName bitwarden-$env:_PACKAGE_VERSION-ia32.nsis.7z
|
||||
Rename-Item -Path .\dist\nsis-web\Bitwarden-$env:_PACKAGE_VERSION-x64.nsis.7z `
|
||||
-NewName bitwarden-$env:_PACKAGE_VERSION-x64.nsis.7z
|
||||
Rename-Item -Path .\dist\nsis-web\Bitwarden-$env:_PACKAGE_VERSION-arm64.nsis.7z `
|
||||
-NewName bitwarden-$env:_PACKAGE_VERSION-arm64.nsis.7z
|
||||
|
||||
- name: Upload portable exe artifact
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
@@ -573,7 +580,7 @@ jobs:
|
||||
if: ${{ needs.setup.outputs.has_secrets == 'true' }}
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
with:
|
||||
name: Bitwarden-Installer-${{ env._PACKAGE_VERSION }}.exe
|
||||
name: Bitwarden-Installer-${{ env._PACKAGE_VERSION }}..exe
|
||||
path: apps/desktop/dist/nsis-web/Bitwarden-Installer-${{ env._PACKAGE_VERSION }}.exe
|
||||
if-no-files-found: error
|
||||
|
||||
@@ -919,6 +926,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
@@ -974,40 +982,40 @@ jobs:
|
||||
ACCOUNT_NAME: bitwardenci
|
||||
CONTAINER_NAME: profiles
|
||||
run: |
|
||||
mkdir -p $HOME/secrets
|
||||
mkdir -p "$HOME/secrets"
|
||||
|
||||
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
|
||||
az storage blob download --account-name "$ACCOUNT_NAME" --container-name "$CONTAINER_NAME" \
|
||||
--name bitwarden_desktop_appstore.provisionprofile \
|
||||
--file $HOME/secrets/bitwarden_desktop_appstore.provisionprofile \
|
||||
--file "$HOME/secrets/bitwarden_desktop_appstore.provisionprofile" \
|
||||
--output none
|
||||
|
||||
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
|
||||
az storage blob download --account-name "$ACCOUNT_NAME" --container-name "$CONTAINER_NAME" \
|
||||
--name bitwarden_desktop_autofill_app_store_2024.provisionprofile \
|
||||
--file $HOME/secrets/bitwarden_desktop_autofill_app_store_2024.provisionprofile \
|
||||
--file "$HOME/secrets/bitwarden_desktop_autofill_app_store_2024.provisionprofile" \
|
||||
--output none
|
||||
|
||||
- name: Get certificates
|
||||
if: ${{ needs.setup.outputs.has_secrets == 'true' }}
|
||||
run: |
|
||||
mkdir -p $HOME/certificates
|
||||
mkdir -p "$HOME/certificates"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/bitwarden-desktop-key |
|
||||
jq -r .value | base64 -d > $HOME/certificates/bitwarden-desktop-key.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/bitwarden-desktop-key.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/appstore-app-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/appstore-app-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/appstore-app-cert.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/appstore-installer-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/appstore-installer-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/appstore-installer-cert.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-app-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/devid-app-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/devid-app-cert.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-installer-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/devid-installer-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/devid-installer-cert.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/macdev-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/macdev-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/macdev-cert.p12"
|
||||
|
||||
- name: Log out from Azure
|
||||
if: ${{ needs.setup.outputs.has_secrets == 'true' }}
|
||||
@@ -1018,9 +1026,9 @@ jobs:
|
||||
env:
|
||||
KEYCHAIN_PASSWORD: ${{ steps.get-kv-secrets.outputs.KEYCHAIN-PASSWORD }}
|
||||
run: |
|
||||
security create-keychain -p $KEYCHAIN_PASSWORD build.keychain
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
security default-keychain -s build.keychain
|
||||
security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
security set-keychain-settings -lut 1200 build.keychain
|
||||
|
||||
security import "$HOME/certificates/bitwarden-desktop-key.p12" -k build.keychain -P "" \
|
||||
@@ -1041,22 +1049,22 @@ jobs:
|
||||
security import "$HOME/certificates/macdev-cert.p12" -k build.keychain -P "" \
|
||||
-T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild
|
||||
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain
|
||||
|
||||
- name: Set up provisioning profiles
|
||||
if: ${{ needs.setup.outputs.has_secrets == 'true' }}
|
||||
run: |
|
||||
cp $HOME/secrets/bitwarden_desktop_appstore.provisionprofile \
|
||||
$GITHUB_WORKSPACE/apps/desktop/bitwarden_desktop_appstore.provisionprofile
|
||||
cp "$HOME/secrets/bitwarden_desktop_appstore.provisionprofile" \
|
||||
"$GITHUB_WORKSPACE/apps/desktop/bitwarden_desktop_appstore.provisionprofile"
|
||||
|
||||
mkdir -p $HOME/Library/MobileDevice/Provisioning\ Profiles
|
||||
export APP_UUID=`grep UUID -A1 -a $HOME/secrets/bitwarden_desktop_appstore.provisionprofile | grep -io "[-A-Z0-9]\{36\}"`
|
||||
export AUTOFILL_UUID=`grep UUID -A1 -a $HOME/secrets/bitwarden_desktop_autofill_app_store_2024.provisionprofile | grep -io "[-A-Z0-9]\{36\}"`
|
||||
mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles"
|
||||
APP_UUID=$(grep UUID -A1 -a "$HOME/secrets/bitwarden_desktop_appstore.provisionprofile" | grep -io "[-A-Z0-9]\{36\}")
|
||||
AUTOFILL_UUID=$(grep UUID -A1 -a "$HOME/secrets/bitwarden_desktop_autofill_app_store_2024.provisionprofile" | grep -io "[-A-Z0-9]\{36\}")
|
||||
|
||||
cp $HOME/secrets/bitwarden_desktop_appstore.provisionprofile \
|
||||
$HOME/Library/MobileDevice/Provisioning\ Profiles/$APP_UUID.provisionprofile
|
||||
cp $HOME/secrets/bitwarden_desktop_autofill_app_store_2024.provisionprofile \
|
||||
$HOME/Library/MobileDevice/Provisioning\ Profiles/$AUTOFILL_UUID.provisionprofile
|
||||
cp "$HOME/secrets/bitwarden_desktop_appstore.provisionprofile" \
|
||||
"$HOME/Library/MobileDevice/Provisioning Profiles/$APP_UUID.provisionprofile"
|
||||
cp "$HOME/secrets/bitwarden_desktop_autofill_app_store_2024.provisionprofile" \
|
||||
"$HOME/Library/MobileDevice/Provisioning Profiles/$AUTOFILL_UUID.provisionprofile"
|
||||
|
||||
- name: Increment version
|
||||
shell: pwsh
|
||||
@@ -1145,6 +1153,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
@@ -1197,39 +1206,39 @@ jobs:
|
||||
ACCOUNT_NAME: bitwardenci
|
||||
CONTAINER_NAME: profiles
|
||||
run: |
|
||||
mkdir -p $HOME/secrets
|
||||
mkdir -p "$HOME/secrets"
|
||||
|
||||
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
|
||||
az storage blob download --account-name "$ACCOUNT_NAME" --container-name "$CONTAINER_NAME" \
|
||||
--name bitwarden_desktop_developer_id.provisionprofile \
|
||||
--file $HOME/secrets/bitwarden_desktop_developer_id.provisionprofile \
|
||||
--file "$HOME/secrets/bitwarden_desktop_developer_id.provisionprofile" \
|
||||
--output none
|
||||
|
||||
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
|
||||
az storage blob download --account-name "$ACCOUNT_NAME" --container-name "$CONTAINER_NAME" \
|
||||
--name bitwarden_desktop_autofill_developer_id.provisionprofile \
|
||||
--file $HOME/secrets/bitwarden_desktop_autofill_developer_id.provisionprofile \
|
||||
--file "$HOME/secrets/bitwarden_desktop_autofill_developer_id.provisionprofile" \
|
||||
--output none
|
||||
|
||||
- name: Get certificates
|
||||
run: |
|
||||
mkdir -p $HOME/certificates
|
||||
mkdir -p "$HOME/certificates"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/bitwarden-desktop-key |
|
||||
jq -r .value | base64 -d > $HOME/certificates/bitwarden-desktop-key.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/bitwarden-desktop-key.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/appstore-app-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/appstore-app-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/appstore-app-cert.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/appstore-installer-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/appstore-installer-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/appstore-installer-cert.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-app-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/devid-app-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/devid-app-cert.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-installer-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/devid-installer-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/devid-installer-cert.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/macdev-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/macdev-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/macdev-cert.p12"
|
||||
|
||||
- name: Log out from Azure
|
||||
uses: bitwarden/gh-actions/azure-logout@main
|
||||
@@ -1238,9 +1247,9 @@ jobs:
|
||||
env:
|
||||
KEYCHAIN_PASSWORD: ${{ steps.get-kv-secrets.outputs.KEYCHAIN-PASSWORD }}
|
||||
run: |
|
||||
security create-keychain -p $KEYCHAIN_PASSWORD build.keychain
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
security default-keychain -s build.keychain
|
||||
security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
security set-keychain-settings -lut 1200 build.keychain
|
||||
|
||||
security import "$HOME/certificates/bitwarden-desktop-key.p12" -k build.keychain -P "" \
|
||||
@@ -1252,21 +1261,21 @@ jobs:
|
||||
security import "$HOME/certificates/devid-installer-cert.p12" -k build.keychain -P "" \
|
||||
-T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild
|
||||
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain
|
||||
|
||||
- name: Set up provisioning profiles
|
||||
run: |
|
||||
cp $HOME/secrets/bitwarden_desktop_developer_id.provisionprofile \
|
||||
$GITHUB_WORKSPACE/apps/desktop/bitwarden_desktop_developer_id.provisionprofile
|
||||
cp "$HOME/secrets/bitwarden_desktop_developer_id.provisionprofile" \
|
||||
"$GITHUB_WORKSPACE/apps/desktop/bitwarden_desktop_developer_id.provisionprofile"
|
||||
|
||||
mkdir -p $HOME/Library/MobileDevice/Provisioning\ Profiles
|
||||
export APP_UUID=`grep UUID -A1 -a $HOME/secrets/bitwarden_desktop_developer_id.provisionprofile | grep -io "[-A-Z0-9]\{36\}"`
|
||||
export AUTOFILL_UUID=`grep UUID -A1 -a $HOME/secrets/bitwarden_desktop_autofill_developer_id.provisionprofile | grep -io "[-A-Z0-9]\{36\}"`
|
||||
mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles"
|
||||
APP_UUID=$(grep UUID -A1 -a "$HOME/secrets/bitwarden_desktop_developer_id.provisionprofile" | grep -io "[-A-Z0-9]\{36\}")
|
||||
AUTOFILL_UUID=$(grep UUID -A1 -a "$HOME/secrets/bitwarden_desktop_autofill_developer_id.provisionprofile" | grep -io "[-A-Z0-9]\{36\}")
|
||||
|
||||
cp $HOME/secrets/bitwarden_desktop_developer_id.provisionprofile \
|
||||
$HOME/Library/MobileDevice/Provisioning\ Profiles/$APP_UUID.provisionprofile
|
||||
cp $HOME/secrets/bitwarden_desktop_autofill_developer_id.provisionprofile \
|
||||
$HOME/Library/MobileDevice/Provisioning\ Profiles/$AUTOFILL_UUID.provisionprofile
|
||||
cp "$HOME/secrets/bitwarden_desktop_developer_id.provisionprofile" \
|
||||
"$HOME/Library/MobileDevice/Provisioning Profiles/$APP_UUID.provisionprofile"
|
||||
cp "$HOME/secrets/bitwarden_desktop_autofill_developer_id.provisionprofile" \
|
||||
"$HOME/Library/MobileDevice/Provisioning Profiles/$AUTOFILL_UUID.provisionprofile"
|
||||
|
||||
- name: Increment version
|
||||
shell: pwsh
|
||||
@@ -1327,20 +1336,22 @@ jobs:
|
||||
|
||||
- name: Unzip Safari artifact
|
||||
run: |
|
||||
SAFARI_DIR=$(find $GITHUB_WORKSPACE/browser-build-artifacts -name 'dist-safari-*.zip')
|
||||
echo $SAFARI_DIR
|
||||
unzip $SAFARI_DIR/dist-safari.zip -d $GITHUB_WORKSPACE/browser-build-artifacts
|
||||
SAFARI_DIR=$(find "$GITHUB_WORKSPACE/browser-build-artifacts" -name 'dist-safari-*.zip')
|
||||
echo "$SAFARI_DIR"
|
||||
unzip "$SAFARI_DIR/dist-safari.zip" -d "$GITHUB_WORKSPACE/browser-build-artifacts"
|
||||
|
||||
- name: Load Safari extension for .dmg
|
||||
run: |
|
||||
mkdir PlugIns
|
||||
cp -r $GITHUB_WORKSPACE/browser-build-artifacts/Safari/dmg/build/Release/safari.appex PlugIns/safari.appex
|
||||
cp -r "$GITHUB_WORKSPACE/browser-build-artifacts/Safari/dmg/build/Release/safari.appex" PlugIns/safari.appex
|
||||
|
||||
- name: Set up private auth key
|
||||
env:
|
||||
_APP_STORE_CONNECT_AUTH_KEY: ${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-AUTH-KEY }}
|
||||
run: |
|
||||
mkdir ~/private_keys
|
||||
cat << EOF > ~/private_keys/AuthKey_6TV9MKN3GP.p8
|
||||
${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-AUTH-KEY }}
|
||||
$_APP_STORE_CONNECT_AUTH_KEY
|
||||
EOF
|
||||
|
||||
- name: Build application (dist)
|
||||
@@ -1403,6 +1414,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
@@ -1462,39 +1474,39 @@ jobs:
|
||||
ACCOUNT_NAME: bitwardenci
|
||||
CONTAINER_NAME: profiles
|
||||
run: |
|
||||
mkdir -p $HOME/secrets
|
||||
mkdir -p "$HOME/secrets"
|
||||
|
||||
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
|
||||
az storage blob download --account-name "$ACCOUNT_NAME" --container-name "$CONTAINER_NAME" \
|
||||
--name bitwarden_desktop_appstore.provisionprofile \
|
||||
--file $HOME/secrets/bitwarden_desktop_appstore.provisionprofile \
|
||||
--file "$HOME/secrets/bitwarden_desktop_appstore.provisionprofile" \
|
||||
--output none
|
||||
|
||||
az storage blob download --account-name $ACCOUNT_NAME --container-name $CONTAINER_NAME \
|
||||
az storage blob download --account-name "$ACCOUNT_NAME" --container-name "$CONTAINER_NAME" \
|
||||
--name bitwarden_desktop_autofill_app_store_2024.provisionprofile \
|
||||
--file $HOME/secrets/bitwarden_desktop_autofill_app_store_2024.provisionprofile \
|
||||
--file "$HOME/secrets/bitwarden_desktop_autofill_app_store_2024.provisionprofile" \
|
||||
--output none
|
||||
|
||||
- name: Get certificates
|
||||
run: |
|
||||
mkdir -p $HOME/certificates
|
||||
mkdir -p "$HOME/certificates"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/bitwarden-desktop-key |
|
||||
jq -r .value | base64 -d > $HOME/certificates/bitwarden-desktop-key.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/bitwarden-desktop-key.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/appstore-app-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/appstore-app-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/appstore-app-cert.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/appstore-installer-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/appstore-installer-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/appstore-installer-cert.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-app-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/devid-app-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/devid-app-cert.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/devid-installer-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/devid-installer-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/devid-installer-cert.p12"
|
||||
|
||||
az keyvault secret show --id https://bitwarden-ci.vault.azure.net/certificates/macdev-cert |
|
||||
jq -r .value | base64 -d > $HOME/certificates/macdev-cert.p12
|
||||
jq -r .value | base64 -d > "$HOME/certificates/macdev-cert.p12"
|
||||
|
||||
- name: Log out from Azure
|
||||
uses: bitwarden/gh-actions/azure-logout@main
|
||||
@@ -1503,9 +1515,9 @@ jobs:
|
||||
env:
|
||||
KEYCHAIN_PASSWORD: ${{ steps.get-kv-secrets.outputs.KEYCHAIN-PASSWORD }}
|
||||
run: |
|
||||
security create-keychain -p $KEYCHAIN_PASSWORD build.keychain
|
||||
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
security default-keychain -s build.keychain
|
||||
security unlock-keychain -p $KEYCHAIN_PASSWORD build.keychain
|
||||
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
|
||||
security set-keychain-settings -lut 1200 build.keychain
|
||||
|
||||
security import "$HOME/certificates/bitwarden-desktop-key.p12" -k build.keychain -P "" \
|
||||
@@ -1517,21 +1529,21 @@ jobs:
|
||||
security import "$HOME/certificates/appstore-installer-cert.p12" -k build.keychain -P "" \
|
||||
-T /usr/bin/codesign -T /usr/bin/security -T /usr/bin/productbuild
|
||||
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k $KEYCHAIN_PASSWORD build.keychain
|
||||
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain
|
||||
|
||||
- name: Set up provisioning profiles
|
||||
run: |
|
||||
cp $HOME/secrets/bitwarden_desktop_appstore.provisionprofile \
|
||||
$GITHUB_WORKSPACE/apps/desktop/bitwarden_desktop_appstore.provisionprofile
|
||||
cp "$HOME/secrets/bitwarden_desktop_appstore.provisionprofile" \
|
||||
"$GITHUB_WORKSPACE/apps/desktop/bitwarden_desktop_appstore.provisionprofile"
|
||||
|
||||
mkdir -p $HOME/Library/MobileDevice/Provisioning\ Profiles
|
||||
export APP_UUID=`grep UUID -A1 -a $HOME/secrets/bitwarden_desktop_appstore.provisionprofile | grep -io "[-A-Z0-9]\{36\}"`
|
||||
export AUTOFILL_UUID=`grep UUID -A1 -a $HOME/secrets/bitwarden_desktop_autofill_app_store_2024.provisionprofile | grep -io "[-A-Z0-9]\{36\}"`
|
||||
mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles"
|
||||
APP_UUID=$(grep UUID -A1 -a "$HOME/secrets/bitwarden_desktop_appstore.provisionprofile" | grep -io "[-A-Z0-9]\{36\}")
|
||||
AUTOFILL_UUID=$(grep UUID -A1 -a "$HOME/secrets/bitwarden_desktop_autofill_app_store_2024.provisionprofile" | grep -io "[-A-Z0-9]\{36\}")
|
||||
|
||||
cp $HOME/secrets/bitwarden_desktop_appstore.provisionprofile \
|
||||
$HOME/Library/MobileDevice/Provisioning\ Profiles/$APP_UUID.provisionprofile
|
||||
cp $HOME/secrets/bitwarden_desktop_autofill_app_store_2024.provisionprofile \
|
||||
$HOME/Library/MobileDevice/Provisioning\ Profiles/$AUTOFILL_UUID.provisionprofile
|
||||
cp "$HOME/secrets/bitwarden_desktop_appstore.provisionprofile" \
|
||||
"$HOME/Library/MobileDevice/Provisioning Profiles/$APP_UUID.provisionprofile"
|
||||
cp "$HOME/secrets/bitwarden_desktop_autofill_app_store_2024.provisionprofile" \
|
||||
"$HOME/Library/MobileDevice/Provisioning Profiles/$AUTOFILL_UUID.provisionprofile"
|
||||
|
||||
- name: Increment version
|
||||
shell: pwsh
|
||||
@@ -1593,20 +1605,22 @@ jobs:
|
||||
|
||||
- name: Unzip Safari artifact
|
||||
run: |
|
||||
SAFARI_DIR=$(find $GITHUB_WORKSPACE/browser-build-artifacts -name 'dist-safari-*.zip')
|
||||
echo $SAFARI_DIR
|
||||
unzip $SAFARI_DIR/dist-safari.zip -d $GITHUB_WORKSPACE/browser-build-artifacts
|
||||
SAFARI_DIR=$(find "$GITHUB_WORKSPACE/browser-build-artifacts" -name 'dist-safari-*.zip')
|
||||
echo "$SAFARI_DIR"
|
||||
unzip "$SAFARI_DIR/dist-safari.zip" -d "$GITHUB_WORKSPACE/browser-build-artifacts"
|
||||
|
||||
- name: Load Safari extension for App Store
|
||||
run: |
|
||||
mkdir PlugIns
|
||||
cp -r $GITHUB_WORKSPACE/browser-build-artifacts/Safari/mas/build/Release/safari.appex PlugIns/safari.appex
|
||||
cp -r "$GITHUB_WORKSPACE/browser-build-artifacts/Safari/mas/build/Release/safari.appex" "PlugIns/safari.appex"
|
||||
|
||||
- name: Set up private auth key
|
||||
env:
|
||||
_APP_STORE_CONNECT_AUTH_KEY: ${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-AUTH-KEY }}
|
||||
run: |
|
||||
mkdir ~/private_keys
|
||||
cat << EOF > ~/private_keys/AuthKey_6TV9MKN3GP.p8
|
||||
${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-AUTH-KEY }}
|
||||
$_APP_STORE_CONNECT_AUTH_KEY
|
||||
EOF
|
||||
|
||||
- name: Build application for App Store
|
||||
@@ -1645,6 +1659,8 @@ jobs:
|
||||
if: |
|
||||
github.event_name != 'pull_request_target'
|
||||
&& (inputs.testflight_distribute || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/rc' || github.ref == 'refs/heads/hotfix-rc-desktop')
|
||||
env:
|
||||
_APP_STORE_CONNECT_TEAM_ISSUER: ${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-TEAM-ISSUER }}
|
||||
run: |
|
||||
brew install gsed
|
||||
|
||||
@@ -1652,7 +1668,7 @@ jobs:
|
||||
|
||||
cat << EOF > ~/secrets/appstoreconnect-fastlane.json
|
||||
{
|
||||
"issuer_id": "${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-TEAM-ISSUER }}",
|
||||
"issuer_id": "$_APP_STORE_CONNECT_TEAM_ISSUER",
|
||||
"key_id": "6TV9MKN3GP",
|
||||
"key": "$KEY_WITHOUT_NEWLINES"
|
||||
}
|
||||
@@ -1671,14 +1687,14 @@ jobs:
|
||||
|
||||
GIT_CHANGE="$(git show -s --format=%s)"
|
||||
|
||||
BRANCH=$(echo $BRANCH | sed 's/refs\/heads\///')
|
||||
BRANCH=$(echo "$BRANCH" | sed 's/refs\/heads\///')
|
||||
|
||||
CHANGELOG="$BRANCH: $GIT_CHANGE"
|
||||
|
||||
fastlane pilot upload \
|
||||
--app_identifier "com.bitwarden.desktop" \
|
||||
--changelog "$CHANGELOG" \
|
||||
--api_key_path $HOME/secrets/appstoreconnect-fastlane.json \
|
||||
--api_key_path "$HOME/secrets/appstoreconnect-fastlane.json" \
|
||||
--pkg "$(find ./dist/mas-universal/Bitwarden*.pkg)"
|
||||
|
||||
- name: Post message to a Slack channel
|
||||
@@ -1724,6 +1740,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Log in to Azure
|
||||
uses: bitwarden/gh-actions/azure-login@main
|
||||
|
||||
59
.github/workflows/build-web.yml
vendored
59
.github/workflows/build-web.yml
vendored
@@ -67,23 +67,24 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Get GitHub sha as version
|
||||
id: version
|
||||
run: echo "value=${GITHUB_SHA:0:7}" >> $GITHUB_OUTPUT
|
||||
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
|
||||
echo "node_version=$NODE_VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Check secrets
|
||||
id: check-secrets
|
||||
run: |
|
||||
has_secrets=${{ secrets.AZURE_CLIENT_ID != '' }}
|
||||
echo "has_secrets=$has_secrets" >> $GITHUB_OUTPUT
|
||||
echo "has_secrets=$has_secrets" >> "$GITHUB_OUTPUT"
|
||||
|
||||
|
||||
build-containers:
|
||||
@@ -137,6 +138,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Get Latest Server Version
|
||||
id: latest-server-version
|
||||
@@ -147,8 +149,10 @@ jobs:
|
||||
|
||||
- name: Set Server Ref
|
||||
id: set-server-ref
|
||||
env:
|
||||
_SERVER_VERSION: ${{ steps.latest-server-version.outputs.version }}
|
||||
run: |
|
||||
SERVER_REF="${{ steps.latest-server-version.outputs.version }}"
|
||||
SERVER_REF="$_SERVER_VERSION"
|
||||
echo "Latest server release version: $SERVER_REF"
|
||||
if [[ "$GITHUB_REF" == "refs/heads/main" ]]; then
|
||||
SERVER_REF="$GITHUB_REF"
|
||||
@@ -158,7 +162,7 @@ jobs:
|
||||
SERVER_REF="refs/heads/main"
|
||||
fi
|
||||
echo "Server ref: $SERVER_REF"
|
||||
echo "server_ref=$SERVER_REF" >> $GITHUB_OUTPUT
|
||||
echo "server_ref=$SERVER_REF" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Check out Server repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
@@ -166,18 +170,19 @@ jobs:
|
||||
path: server
|
||||
repository: bitwarden/server
|
||||
ref: ${{ steps.set-server-ref.outputs.server_ref }}
|
||||
persist-credentials: false
|
||||
|
||||
- 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
|
||||
IFS="," read -a publish_branches <<< "$PUBLISH_BRANCHES"
|
||||
|
||||
if [[ " ${publish_branches[*]} " =~ " ${GITHUB_REF:11} " ]]; then
|
||||
echo "is_publish_branch=true" >> $GITHUB_ENV
|
||||
echo "is_publish_branch=true" >> "$GITHUB_ENV"
|
||||
else
|
||||
echo "is_publish_branch=false" >> $GITHUB_ENV
|
||||
echo "is_publish_branch=false" >> "$GITHUB_ENV"
|
||||
fi
|
||||
|
||||
- name: Add Git metadata to build version
|
||||
@@ -217,11 +222,13 @@ jobs:
|
||||
|
||||
- name: Log into Prod container registry
|
||||
if: ${{ needs.setup.outputs.has_secrets == 'true' }}
|
||||
run: az acr login -n ${_AZ_REGISTRY%.azurecr.io}
|
||||
run: az acr login -n "${_AZ_REGISTRY%.azurecr.io}"
|
||||
|
||||
########## Generate image tag and build Docker image ##########
|
||||
- name: Generate container image tag
|
||||
id: tag
|
||||
env:
|
||||
_TAG_EXTENSION: ${{ github.event.inputs.custom_tag_extension }}
|
||||
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
|
||||
@@ -231,7 +238,7 @@ jobs:
|
||||
|
||||
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="$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
|
||||
|
||||
@@ -239,13 +246,13 @@ jobs:
|
||||
IMAGE_TAG=dev
|
||||
fi
|
||||
|
||||
TAG_EXTENSION=${{ github.event.inputs.custom_tag_extension }}
|
||||
TAG_EXTENSION="$_TAG_EXTENSION"
|
||||
|
||||
if [[ $TAG_EXTENSION ]]; then
|
||||
IMAGE_TAG=$IMAGE_TAG-$TAG_EXTENSION
|
||||
IMAGE_TAG="$IMAGE_TAG-$TAG_EXTENSION"
|
||||
fi
|
||||
|
||||
echo "image_tag=$IMAGE_TAG" >> $GITHUB_OUTPUT
|
||||
echo "image_tag=$IMAGE_TAG" >> "$GITHUB_OUTPUT"
|
||||
|
||||
########## Build Image ##########
|
||||
- name: Generate image full name
|
||||
@@ -253,7 +260,7 @@ jobs:
|
||||
env:
|
||||
IMAGE_TAG: ${{ steps.tag.outputs.image_tag }}
|
||||
PROJECT_NAME: ${{ matrix.image_name }}
|
||||
run: echo "name=$_AZ_REGISTRY/${PROJECT_NAME}:${IMAGE_TAG}" >> $GITHUB_OUTPUT
|
||||
run: echo "name=$_AZ_REGISTRY/${PROJECT_NAME}:${IMAGE_TAG}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Build Docker image
|
||||
id: build-container
|
||||
@@ -276,7 +283,7 @@ jobs:
|
||||
if: ${{ needs.setup.outputs.has_secrets == 'true' }}
|
||||
env:
|
||||
IMAGE_NAME: ${{ steps.image-name.outputs.name }}
|
||||
run: docker push $IMAGE_NAME
|
||||
run: docker push "$IMAGE_NAME"
|
||||
|
||||
- name: Zip project
|
||||
working-directory: apps/web
|
||||
@@ -284,10 +291,10 @@ jobs:
|
||||
IMAGE_NAME: ${{ steps.image-name.outputs.name }}
|
||||
run: |
|
||||
mkdir build
|
||||
docker run --rm --volume $(pwd)/build:/temp --entrypoint sh \
|
||||
$IMAGE_NAME -c "cp -r ./ /temp"
|
||||
docker run --rm --volume "$(pwd)/build":/temp --entrypoint sh \
|
||||
"$IMAGE_NAME" -c "cp -r ./ /temp"
|
||||
|
||||
zip -r web-${{ env._VERSION }}-${{ matrix.artifact_name }}.zip build
|
||||
zip -r web-$_VERSION-${{ matrix.artifact_name }}.zip build
|
||||
|
||||
- name: Upload ${{ matrix.artifact_name }} artifact
|
||||
uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0
|
||||
@@ -306,12 +313,13 @@ jobs:
|
||||
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} "
|
||||
IFS=',' read -r -a tags_array <<< "${TAGS}"
|
||||
images=()
|
||||
for tag in "${tags_array[@]}"; do
|
||||
images+=("${tag}@${DIGEST}")
|
||||
done
|
||||
cosign sign --yes ${images}
|
||||
cosign sign --yes "${images[@]}"
|
||||
echo "images=${images[*]}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Scan Docker image
|
||||
if: ${{ needs.setup.outputs.has_secrets == 'true' }}
|
||||
@@ -324,14 +332,14 @@ jobs:
|
||||
|
||||
- name: Upload Grype results to GitHub
|
||||
if: ${{ needs.setup.outputs.has_secrets == 'true' }}
|
||||
uses: github/codeql-action/upload-sarif@d68b2d4edb4189fd2a5366ac14e72027bd4b37dd # v3.28.2
|
||||
uses: github/codeql-action/upload-sarif@573acd9552f33577783abde4acb66a1058e762e5 # codeql-bundle-v2.23.1
|
||||
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
|
||||
run: docker logout "$_AZ_REGISTRY"
|
||||
|
||||
- name: Log out from Azure
|
||||
if: ${{ needs.setup.outputs.has_secrets == 'true' }}
|
||||
@@ -352,6 +360,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Log in to Azure
|
||||
uses: bitwarden/gh-actions/azure-login@main
|
||||
|
||||
3
.github/workflows/chromatic.yml
vendored
3
.github/workflows/chromatic.yml
vendored
@@ -35,6 +35,7 @@ jobs:
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Get changed files
|
||||
id: get-changed-files-for-chromatic
|
||||
@@ -54,7 +55,7 @@ jobs:
|
||||
run: |
|
||||
NODE_NVMRC=$(cat .nvmrc)
|
||||
NODE_VERSION=${NODE_NVMRC/v/''}
|
||||
echo "node_version=$NODE_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "node_version=$NODE_VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
|
||||
1
.github/workflows/crowdin-pull.yml
vendored
1
.github/workflows/crowdin-pull.yml
vendored
@@ -59,6 +59,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
persist-credentials: false
|
||||
|
||||
- name: Download translations
|
||||
uses: bitwarden/gh-actions/crowdin@main
|
||||
|
||||
130
.github/workflows/deploy-web.yml
vendored
130
.github/workflows/deploy-web.yml
vendored
@@ -74,56 +74,58 @@ jobs:
|
||||
steps:
|
||||
- name: Configure
|
||||
id: config
|
||||
env:
|
||||
_ENVIRONMENT: ${{ inputs.environment }}
|
||||
run: |
|
||||
ENV_NAME_LOWER=$(echo "${{ inputs.environment }}" | awk '{print tolower($0)}')
|
||||
echo "configuring the Web deploy for ${{ inputs.environment }}"
|
||||
echo "environment=${{ inputs.environment }}" >> $GITHUB_OUTPUT
|
||||
ENV_NAME_LOWER=$(echo "$_ENVIRONMENT" | awk '{print tolower($0)}')
|
||||
echo "configuring the Web deploy for _ENVIRONMENT"
|
||||
echo "environment=$_ENVIRONMENT" >> "$GITHUB_OUTPUT"
|
||||
|
||||
case ${{ inputs.environment }} in
|
||||
case $_ENVIRONMENT in
|
||||
"USQA")
|
||||
echo "azure_login_client_key_name=AZURE_CLIENT_ID_USQA" >> $GITHUB_OUTPUT
|
||||
echo "azure_login_subscription_id_key_name=AZURE_SUBSCRIPTION_ID_USQA" >> $GITHUB_OUTPUT
|
||||
echo "retrieve_secrets_keyvault=bw-webvault-rlktusqa-kv" >> $GITHUB_OUTPUT
|
||||
echo "environment_artifact=web-*-cloud-QA.zip" >> $GITHUB_OUTPUT
|
||||
echo "environment_name=Web Vault - US QA Cloud" >> $GITHUB_OUTPUT
|
||||
echo "environment_url=http://vault.$ENV_NAME_LOWER.bitwarden.pw" >> $GITHUB_OUTPUT
|
||||
echo "slack_channel_name=alerts-deploy-qa" >> $GITHUB_OUTPUT
|
||||
echo "azure_login_client_key_name=AZURE_CLIENT_ID_USQA" >> "$GITHUB_OUTPUT"
|
||||
echo "azure_login_subscription_id_key_name=AZURE_SUBSCRIPTION_ID_USQA" >> "$GITHUB_OUTPUT"
|
||||
echo "retrieve_secrets_keyvault=bw-webvault-rlktusqa-kv" >> "$GITHUB_OUTPUT"
|
||||
echo "environment_artifact=web-*-cloud-QA.zip" >> "$GITHUB_OUTPUT"
|
||||
echo "environment_name=Web Vault - US QA Cloud" >> "$GITHUB_OUTPUT"
|
||||
echo "environment_url=http://vault.$ENV_NAME_LOWER.bitwarden.pw" >> "$GITHUB_OUTPUT"
|
||||
echo "slack_channel_name=alerts-deploy-qa" >> "$GITHUB_OUTPUT"
|
||||
;;
|
||||
"EUQA")
|
||||
echo "azure_login_client_key_name=AZURE_CLIENT_ID_EUQA" >> $GITHUB_OUTPUT
|
||||
echo "azure_login_subscription_id_key_name=AZURE_SUBSCRIPTION_ID_EUQA" >> $GITHUB_OUTPUT
|
||||
echo "retrieve_secrets_keyvault=webvaulteu-westeurope-qa" >> $GITHUB_OUTPUT
|
||||
echo "environment_artifact=web-*-cloud-euqa.zip" >> $GITHUB_OUTPUT
|
||||
echo "environment_name=Web Vault - EU QA Cloud" >> $GITHUB_OUTPUT
|
||||
echo "environment_url=http://vault.$ENV_NAME_LOWER.bitwarden.pw" >> $GITHUB_OUTPUT
|
||||
echo "slack_channel_name=alerts-deploy-qa" >> $GITHUB_OUTPUT
|
||||
echo "azure_login_client_key_name=AZURE_CLIENT_ID_EUQA" >> "$GITHUB_OUTPUT"
|
||||
echo "azure_login_subscription_id_key_name=AZURE_SUBSCRIPTION_ID_EUQA" >> "$GITHUB_OUTPUT"
|
||||
echo "retrieve_secrets_keyvault=webvaulteu-westeurope-qa" >> "$GITHUB_OUTPUT"
|
||||
echo "environment_artifact=web-*-cloud-euqa.zip" >> "$GITHUB_OUTPUT"
|
||||
echo "environment_name=Web Vault - EU QA Cloud" >> "$GITHUB_OUTPUT"
|
||||
echo "environment_url=http://vault.$ENV_NAME_LOWER.bitwarden.pw" >> "$GITHUB_OUTPUT"
|
||||
echo "slack_channel_name=alerts-deploy-qa" >> "$GITHUB_OUTPUT"
|
||||
;;
|
||||
"USPROD")
|
||||
echo "azure_login_client_key_name=AZURE_CLIENT_ID_USPROD" >> $GITHUB_OUTPUT
|
||||
echo "azure_login_subscription_id_key_name=AZURE_SUBSCRIPTION_ID_USPROD" >> $GITHUB_OUTPUT
|
||||
echo "retrieve_secrets_keyvault=bw-webvault-klrt-kv" >> $GITHUB_OUTPUT
|
||||
echo "environment_artifact=web-*-cloud-COMMERCIAL.zip" >> $GITHUB_OUTPUT
|
||||
echo "environment_name=Web Vault - US Production Cloud" >> $GITHUB_OUTPUT
|
||||
echo "environment_url=http://vault.bitwarden.com" >> $GITHUB_OUTPUT
|
||||
echo "slack_channel_name=alerts-deploy-prd" >> $GITHUB_OUTPUT
|
||||
echo "azure_login_client_key_name=AZURE_CLIENT_ID_USPROD" >> "$GITHUB_OUTPUT"
|
||||
echo "azure_login_subscription_id_key_name=AZURE_SUBSCRIPTION_ID_USPROD" >> "$GITHUB_OUTPUT"
|
||||
echo "retrieve_secrets_keyvault=bw-webvault-klrt-kv" >> "$GITHUB_OUTPUT"
|
||||
echo "environment_artifact=web-*-cloud-COMMERCIAL.zip" >> "$GITHUB_OUTPUT"
|
||||
echo "environment_name=Web Vault - US Production Cloud" >> "$GITHUB_OUTPUT"
|
||||
echo "environment_url=http://vault.bitwarden.com" >> "$GITHUB_OUTPUT"
|
||||
echo "slack_channel_name=alerts-deploy-prd" >> "$GITHUB_OUTPUT"
|
||||
;;
|
||||
"EUPROD")
|
||||
echo "azure_login_client_key_name=AZURE_CLIENT_ID_EUPROD" >> $GITHUB_OUTPUT
|
||||
echo "azure_login_subscription_id_key_name=AZURE_SUBSCRIPTION_ID_EUPROD" >> $GITHUB_OUTPUT
|
||||
echo "retrieve_secrets_keyvault=webvault-westeurope-prod" >> $GITHUB_OUTPUT
|
||||
echo "environment_artifact=web-*-cloud-euprd.zip" >> $GITHUB_OUTPUT
|
||||
echo "environment_name=Web Vault - EU Production Cloud" >> $GITHUB_OUTPUT
|
||||
echo "environment_url=http://vault.bitwarden.eu" >> $GITHUB_OUTPUT
|
||||
echo "slack_channel_name=alerts-deploy-prd" >> $GITHUB_OUTPUT
|
||||
echo "azure_login_client_key_name=AZURE_CLIENT_ID_EUPROD" >> "$GITHUB_OUTPUT"
|
||||
echo "azure_login_subscription_id_key_name=AZURE_SUBSCRIPTION_ID_EUPROD" >> "$GITHUB_OUTPUT"
|
||||
echo "retrieve_secrets_keyvault=webvault-westeurope-prod" >> "$GITHUB_OUTPUT"
|
||||
echo "environment_artifact=web-*-cloud-euprd.zip" >> "$GITHUB_OUTPUT"
|
||||
echo "environment_name=Web Vault - EU Production Cloud" >> "$GITHUB_OUTPUT"
|
||||
echo "environment_url=http://vault.bitwarden.eu" >> "$GITHUB_OUTPUT"
|
||||
echo "slack_channel_name=alerts-deploy-prd" >> "$GITHUB_OUTPUT"
|
||||
;;
|
||||
"USDEV")
|
||||
echo "azure_login_client_key_name=AZURE_CLIENT_ID_USDEV" >> $GITHUB_OUTPUT
|
||||
echo "azure_login_subscription_id_key_name=AZURE_SUBSCRIPTION_ID_USDEV" >> $GITHUB_OUTPUT
|
||||
echo "retrieve_secrets_keyvault=webvault-eastus-dev" >> $GITHUB_OUTPUT
|
||||
echo "environment_artifact=web-*-cloud-usdev.zip" >> $GITHUB_OUTPUT
|
||||
echo "environment_name=Web Vault - US Development Cloud" >> $GITHUB_OUTPUT
|
||||
echo "environment_url=http://vault.$ENV_NAME_LOWER.bitwarden.pw" >> $GITHUB_OUTPUT
|
||||
echo "slack_channel_name=alerts-deploy-dev" >> $GITHUB_OUTPUT
|
||||
echo "azure_login_client_key_name=AZURE_CLIENT_ID_USDEV" >> "$GITHUB_OUTPUT"
|
||||
echo "azure_login_subscription_id_key_name=AZURE_SUBSCRIPTION_ID_USDEV" >> "$GITHUB_OUTPUT"
|
||||
echo "retrieve_secrets_keyvault=webvault-eastus-dev" >> "$GITHUB_OUTPUT"
|
||||
echo "environment_artifact=web-*-cloud-usdev.zip" >> "$GITHUB_OUTPUT"
|
||||
echo "environment_name=Web Vault - US Development Cloud" >> "$GITHUB_OUTPUT"
|
||||
echo "environment_url=http://vault.$ENV_NAME_LOWER.bitwarden.pw" >> "$GITHUB_OUTPUT"
|
||||
echo "slack_channel_name=alerts-deploy-dev" >> "$GITHUB_OUTPUT"
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -131,12 +133,14 @@ jobs:
|
||||
env:
|
||||
BUILD_WEB_RUN_ID: ${{ inputs.build-web-run-id }}
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
_ENVIRONMENT: ${{ inputs.environment }}
|
||||
_BRANCH_OR_TAG: ${{ inputs.branch-or-tag }}
|
||||
run: |
|
||||
BRANCH_OR_TAG_LOWER=""
|
||||
if [[ "$BUILD_WEB_RUN_ID" == "" ]]; then
|
||||
BRANCH_OR_TAG_LOWER=$(echo ${{ inputs.branch-or-tag }} | awk '{print tolower($0)}')
|
||||
BRANCH_OR_TAG_LOWER=$(echo "$_BRANCH_OR_TAG" | awk '{print tolower($0)}')
|
||||
else
|
||||
BRANCH_OR_TAG_LOWER=$(gh api /repos/bitwarden/clients/actions/runs/$BUILD_WEB_RUN_ID/artifacts --jq '.artifacts[0].workflow_run.head_branch' | awk '{print tolower($0)}')
|
||||
BRANCH_OR_TAG_LOWER=$(gh api "/repos/bitwarden/clients/actions/runs/$BUILD_WEB_RUN_ID/artifacts" --jq '.artifacts[0].workflow_run.head_branch' | awk '{print tolower($0)}')
|
||||
fi
|
||||
|
||||
echo "Branch/Tag: $BRANCH_OR_TAG_LOWER"
|
||||
@@ -151,23 +155,23 @@ jobs:
|
||||
DEV_ALLOWED_TAGS_PATTERN='main'
|
||||
|
||||
if [[ \
|
||||
${{ inputs.environment }} =~ \.*($PROD_ENV_PATTERN)\.* && \
|
||||
$_ENVIRONMENT =~ \.*($PROD_ENV_PATTERN)\.* && \
|
||||
! "$BRANCH_OR_TAG_LOWER" =~ ^($PROD_ALLOWED_TAGS_PATTERN).* \
|
||||
]] || [[ \
|
||||
${{ inputs.environment }} =~ \.*($QA_ENV_PATTERN)\.* && \
|
||||
$_ENVIRONMENT =~ \.*($QA_ENV_PATTERN)\.* && \
|
||||
! "$BRANCH_OR_TAG_LOWER" =~ ^($QA_ALLOWED_TAGS_PATTERN).* \
|
||||
]] || [[ \
|
||||
${{ inputs.environment }} =~ \.*($DEV_ENV_PATTERN)\.* && \
|
||||
$BRANCH_OR_TAG_LOWER != $DEV_ALLOWED_TAGS_PATTERN \
|
||||
$_ENVIRONMENT =~ \.*($DEV_ENV_PATTERN)\.* && \
|
||||
$BRANCH_OR_TAG_LOWER != "$DEV_ALLOWED_TAGS_PATTERN" \
|
||||
]]; then
|
||||
echo "!Deployment blocked!"
|
||||
echo "Attempting to deploy a tag that is not allowed in ${{ inputs.environment }} environment"
|
||||
echo "Attempting to deploy a tag that is not allowed in $_ENVIRONMENT environment"
|
||||
echo
|
||||
echo "Environment: ${{ inputs.environment }}"
|
||||
echo "Environment: $_ENVIRONMENT"
|
||||
echo "Tag: $BRANCH_OR_TAG_LOWER"
|
||||
exit 1
|
||||
else
|
||||
echo "The input Branch/Tag: '$BRANCH_OR_TAG_LOWER' is allowed to deploy on ${{ inputs.environment }} environment"
|
||||
echo "The input Branch/Tag: '$BRANCH_OR_TAG_LOWER' is allowed to deploy on $_ENVIRONMENT environment"
|
||||
fi
|
||||
|
||||
approval:
|
||||
@@ -251,19 +255,24 @@ jobs:
|
||||
id: set-artifact-commit
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
_BUILD_WEB_RUN_ID: ${{ inputs.build-web-run-id }}
|
||||
_ARTIFACT_BUILD_COMMIT: ${{ steps.download-latest-artifacts-run-id.outputs.artifact-build-commit }}
|
||||
_DOWNLOAD_LATEST_ARTIFACTS_OUTCOME: ${{ steps.download-latest-artifacts.outcome }}
|
||||
_WORKFLOW_ID: ${{ steps.trigger-build-web.outputs.workflow_id}}
|
||||
_ARTIFACT_COMMIT: ${{ steps.download-latest-artifacts.outputs.artifact-build-commit }}
|
||||
run: |
|
||||
# If run-id was used, get the commit from the download-latest-artifacts-run-id step
|
||||
if [ "${{ inputs.build-web-run-id }}" ]; then
|
||||
echo "commit=${{ steps.download-latest-artifacts-run-id.outputs.artifact-build-commit }}" >> $GITHUB_OUTPUT
|
||||
if [ "$_BUILD_WEB_RUN_ID" ]; then
|
||||
echo "commit=$_ARTIFACT_BUILD_COMMIT" >> "$GITHUB_OUTPUT"
|
||||
|
||||
elif [ "${{ steps.download-latest-artifacts.outcome }}" == "failure" ]; then
|
||||
elif [ "$_DOWNLOAD_LATEST_ARTIFACTS_OUTCOME" == "failure" ]; then
|
||||
# If the download-latest-artifacts step failed, query the GH API to get the commit SHA of the artifact that was just built with trigger-build-web.
|
||||
commit=$(gh api /repos/bitwarden/clients/actions/runs/${{ steps.trigger-build-web.outputs.workflow_id }}/artifacts --jq '.artifacts[0].workflow_run.head_sha')
|
||||
echo "commit=$commit" >> $GITHUB_OUTPUT
|
||||
commit=$(gh api "/repos/bitwarden/clients/actions/runs/$_WORKFLOW_ID/artifacts" --jq '.artifacts[0].workflow_run.head_sha')
|
||||
echo "commit=$commit" >> "$GITHUB_OUTPUT"
|
||||
|
||||
else
|
||||
# Set the commit to the output of step download-latest-artifacts.
|
||||
echo "commit=${{ steps.download-latest-artifacts.outputs.artifact-build-commit }}" >> $GITHUB_OUTPUT
|
||||
echo "commit=$_ARTIFACT_COMMIT" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
notify-start:
|
||||
@@ -299,12 +308,14 @@ jobs:
|
||||
name: Display commit
|
||||
needs: artifact-check
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
_ARTIFACT_BUILD_COMMIT_SHA: ${{ needs.artifact-check.outputs.artifact_build_commit }}
|
||||
steps:
|
||||
- name: Display commit SHA
|
||||
run: |
|
||||
REPO_URL="https://github.com/bitwarden/clients/commit"
|
||||
COMMIT_SHA="${{ needs.artifact-check.outputs.artifact_build_commit }}"
|
||||
echo ":steam_locomotive: View [commit]($REPO_URL/$COMMIT_SHA)" >> $GITHUB_STEP_SUMMARY
|
||||
COMMIT_SHA="$_ARTIFACT_BUILD_COMMIT_SHA"
|
||||
echo ":steam_locomotive: View [commit]($REPO_URL/$COMMIT_SHA)" >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
azure-deploy:
|
||||
name: Deploy Web Vault to ${{ inputs.environment }} Storage Account
|
||||
@@ -358,7 +369,7 @@ jobs:
|
||||
|
||||
- name: Unzip build asset
|
||||
working-directory: apps/web
|
||||
run: unzip ${{ env._ENVIRONMENT_ARTIFACT }}
|
||||
run: unzip "$_ENVIRONMENT_ARTIFACT"
|
||||
|
||||
- name: Login to Azure
|
||||
uses: bitwarden/gh-actions/azure-login@main
|
||||
@@ -379,9 +390,10 @@ jobs:
|
||||
env:
|
||||
AZCOPY_AUTO_LOGIN_TYPE: AZCLI
|
||||
AZCOPY_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
|
||||
_VAULT_NAME: ${{ steps.retrieve-secrets-azcopy.outputs.sa-bitwarden-web-vault-name }}.
|
||||
run: |
|
||||
azcopy sync ./build 'https://${{ steps.retrieve-secrets-azcopy.outputs.sa-bitwarden-web-vault-name }}.blob.core.windows.net/$web/' \
|
||||
--delete-destination=${{ inputs.force-delete-destination }} --compare-hash="MD5"
|
||||
azcopy sync ./build "https://$_VAULT_NAME.blob.core.windows.net/$web/" \
|
||||
--delete-destination="${{ inputs.force-delete-destination }}" --compare-hash="MD5"
|
||||
|
||||
- name: Log out from Azure
|
||||
uses: bitwarden/gh-actions/azure-logout@main
|
||||
|
||||
1
.github/workflows/lint-crowdin-config.yml
vendored
1
.github/workflows/lint-crowdin-config.yml
vendored
@@ -25,6 +25,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
fetch-depth: 1
|
||||
persist-credentials: false
|
||||
|
||||
- name: Log in to Azure
|
||||
uses: bitwarden/gh-actions/azure-login@main
|
||||
|
||||
6
.github/workflows/lint.yml
vendored
6
.github/workflows/lint.yml
vendored
@@ -32,6 +32,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Lint filenames (no capital characters)
|
||||
run: |
|
||||
@@ -58,7 +60,7 @@ jobs:
|
||||
run: |
|
||||
NODE_NVMRC=$(cat .nvmrc)
|
||||
NODE_VERSION=${NODE_NVMRC/v/''}
|
||||
echo "node_version=$NODE_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "node_version=$NODE_VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
@@ -90,6 +92,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Check Rust version
|
||||
run: rustup --version
|
||||
|
||||
6
.github/workflows/locales-lint.yml
vendored
6
.github/workflows/locales-lint.yml
vendored
@@ -18,17 +18,19 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: Checkout base branch repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.base.sha }}
|
||||
path: base
|
||||
persist-credentials: false
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Compare
|
||||
run: |
|
||||
npm run test:locales
|
||||
if [ $? -eq 0 ]; then
|
||||
if npm run test:locales; then
|
||||
echo "Lint check successful."
|
||||
else
|
||||
echo "Lint check failed."
|
||||
|
||||
3
.github/workflows/nx.yml
vendored
3
.github/workflows/nx.yml
vendored
@@ -15,6 +15,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Get Node Version
|
||||
id: retrieve-node-version
|
||||
@@ -22,7 +23,7 @@ jobs:
|
||||
run: |
|
||||
NODE_NVMRC=$(cat .nvmrc)
|
||||
NODE_VERSION=${NODE_NVMRC/v/''}
|
||||
echo "node_version=$NODE_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "node_version=$NODE_VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
|
||||
28
.github/workflows/publish-cli.yml
vendored
28
.github/workflows/publish-cli.yml
vendored
@@ -65,14 +65,16 @@ jobs:
|
||||
|
||||
- name: Version output
|
||||
id: version-output
|
||||
env:
|
||||
_INPUT_VERSION: ${{ inputs.version }}
|
||||
run: |
|
||||
if [[ "${{ inputs.version }}" == "latest" || "${{ inputs.version }}" == "" ]]; then
|
||||
if [[ "$_INPUT_VERSION" == "latest" || "$_INPUT_VERSION" == "" ]]; then
|
||||
VERSION=$(curl "https://api.github.com/repos/bitwarden/clients/releases" | jq -c '.[] | select(.tag_name | contains("cli")) | .tag_name' | head -1 | grep -ohE '20[0-9]{2}\.([1-9]|1[0-2])\.[0-9]+')
|
||||
echo "Latest Released Version: $VERSION"
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "Release Version: ${{ inputs.version }}"
|
||||
echo "version=${{ inputs.version }}" >> $GITHUB_OUTPUT
|
||||
echo "Release Version: $_INPUT_VERSION"
|
||||
echo "version=$_INPUT_VERSION" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Create GitHub deployment
|
||||
@@ -100,6 +102,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Log in to Azure
|
||||
uses: bitwarden/gh-actions/azure-login@main
|
||||
@@ -122,14 +126,14 @@ jobs:
|
||||
uses: samuelmeuli/action-snapcraft@fceeb3c308e76f3487e72ef608618de625fb7fe8 # v3.0.1
|
||||
|
||||
- name: Download artifacts
|
||||
run: wget https://github.com/bitwarden/clients/releases/download/cli-v${{ env._PKG_VERSION }}/bw_${{ env._PKG_VERSION }}_amd64.snap
|
||||
run: wget "https://github.com/bitwarden/clients/releases/download/cli-v$_PKG_VERSION/bw_$_PKG_VERSION_amd64.snap"
|
||||
|
||||
- name: Publish Snap & logout
|
||||
if: ${{ inputs.publish_type != 'Dry Run' }}
|
||||
env:
|
||||
SNAPCRAFT_STORE_CREDENTIALS: ${{ steps.retrieve-secrets.outputs.snapcraft-store-token }}
|
||||
run: |
|
||||
snapcraft upload bw_${{ env._PKG_VERSION }}_amd64.snap --release stable
|
||||
snapcraft upload "bw_$_PKG_VERSION_amd64.snap" --release stable
|
||||
snapcraft logout
|
||||
|
||||
choco:
|
||||
@@ -146,6 +150,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Log in to Azure
|
||||
uses: bitwarden/gh-actions/azure-login@main
|
||||
@@ -173,7 +179,7 @@ jobs:
|
||||
run: New-Item -ItemType directory -Path ./dist
|
||||
|
||||
- name: Download artifacts
|
||||
run: Invoke-WebRequest -Uri "https://github.com/bitwarden/clients/releases/download/cli-v${{ env._PKG_VERSION }}/bitwarden-cli.${{ env._PKG_VERSION }}.nupkg" -OutFile bitwarden-cli.${{ env._PKG_VERSION }}.nupkg
|
||||
run: Invoke-WebRequest -Uri "https://github.com/bitwarden/clients/releases/download/cli-v$_PKG_VERSION/bitwarden-cli.$_PKG_VERSION.nupkg" -OutFile bitwarden-cli.$_PKG_VERSION.nupkg
|
||||
working-directory: apps/cli/dist
|
||||
|
||||
- name: Push to Chocolatey
|
||||
@@ -196,6 +202,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Get Node version
|
||||
id: retrieve-node-version
|
||||
@@ -203,7 +211,7 @@ jobs:
|
||||
run: |
|
||||
NODE_NVMRC=$(cat .nvmrc)
|
||||
NODE_VERSION=${NODE_NVMRC/v/''}
|
||||
echo "node_version=$NODE_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "node_version=$NODE_VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
@@ -219,8 +227,8 @@ jobs:
|
||||
- name: Download and set up artifact
|
||||
run: |
|
||||
mkdir -p build
|
||||
wget https://github.com/bitwarden/clients/releases/download/cli-v${{ env._PKG_VERSION }}/bitwarden-cli-${{ env._PKG_VERSION }}-npm-build.zip
|
||||
unzip bitwarden-cli-${{ env._PKG_VERSION }}-npm-build.zip -d build
|
||||
wget "https://github.com/bitwarden/clients/releases/download/cli-v$_PKG_VERSION/bitwarden-cli-$_PKG_VERSION-npm-build.zip"
|
||||
unzip "bitwarden-cli-$_PKG_VERSION-npm-build.zip" -d build
|
||||
|
||||
- name: Publish NPM
|
||||
if: ${{ inputs.publish_type != 'Dry Run' }}
|
||||
|
||||
72
.github/workflows/publish-desktop.yml
vendored
72
.github/workflows/publish-desktop.yml
vendored
@@ -72,39 +72,47 @@ jobs:
|
||||
|
||||
- name: Check Publish Version
|
||||
id: version
|
||||
env:
|
||||
_INPUT_VERSION: ${{ inputs.version }}
|
||||
run: |
|
||||
if [[ "${{ inputs.version }}" == "latest" || "${{ inputs.version }}" == "" ]]; then
|
||||
TAG_NAME=$(curl "https://api.github.com/repos/bitwarden/clients/releases" | jq -c '.[] | select(.tag_name | contains("desktop")) | .tag_name' | head -1 | cut -d '"' -f 2)
|
||||
VERSION=$(echo $TAG_NAME | sed "s/desktop-v//")
|
||||
if [[ "$_INPUT_VERSION" == "latest" || "$_INPUT_VERSION" == "" ]]; then
|
||||
TAG_NAME=$(curl "https://api.github.com/repos/bitwarden/clients/releases" \
|
||||
| jq -c '.[] | select(.tag_name | contains("desktop")) | .tag_name' \
|
||||
| head -1 | cut -d '"' -f 2)
|
||||
VERSION="${TAG_NAME#desktop-v}"
|
||||
|
||||
echo "Latest Released Version: $VERSION"
|
||||
echo "version=$VERSION" >> $GITHUB_OUTPUT
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
echo "Tag name: $TAG_NAME"
|
||||
echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT
|
||||
echo "tag_name=$TAG_NAME" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "Release Version: ${{ inputs.version }}"
|
||||
echo "version=${{ inputs.version }}"
|
||||
VERSION="$_INPUT_VERSION"
|
||||
TAG_NAME="desktop-v$VERSION"
|
||||
|
||||
TAG_NAME="desktop-v${{ inputs.version }}"
|
||||
echo "Release Version: $VERSION"
|
||||
echo "version=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
echo "Tag name: $TAG_NAME"
|
||||
echo "tag_name=$TAG_NAME" >> $GITHUB_OUTPUT
|
||||
echo "tag_name=$TAG_NAME" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Get Version Channel
|
||||
id: release_channel
|
||||
env:
|
||||
_VERSION: ${{ steps.version.outputs.version }}
|
||||
run: |
|
||||
case "${{ steps.version.outputs.version }}" in
|
||||
case "${_VERSION}" in
|
||||
*"alpha"*)
|
||||
echo "channel=alpha" >> $GITHUB_OUTPUT
|
||||
echo "channel=alpha" >> "$GITHUB_OUTPUT"
|
||||
echo "[!] We do not yet support 'alpha'"
|
||||
exit 1
|
||||
;;
|
||||
*"beta"*)
|
||||
echo "channel=beta" >> $GITHUB_OUTPUT
|
||||
echo "channel=beta" >> "$GITHUB_OUTPUT"
|
||||
;;
|
||||
*)
|
||||
echo "channel=latest" >> $GITHUB_OUTPUT
|
||||
echo "channel=latest" >> "$GITHUB_OUTPUT"
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -159,16 +167,16 @@ jobs:
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
working-directory: apps/desktop/artifacts
|
||||
run: gh release download ${{ env._RELEASE_TAG }} -R bitwarden/clients
|
||||
run: gh release download "$_RELEASE_TAG" -R bitwarden/clients
|
||||
|
||||
- name: Set staged rollout percentage
|
||||
env:
|
||||
RELEASE_CHANNEL: ${{ needs.setup.outputs.release_channel }}
|
||||
ROLLOUT_PCT: ${{ inputs.electron_rollout_percentage }}
|
||||
run: |
|
||||
echo "stagingPercentage: ${ROLLOUT_PCT}" >> apps/desktop/artifacts/${RELEASE_CHANNEL}.yml
|
||||
echo "stagingPercentage: ${ROLLOUT_PCT}" >> apps/desktop/artifacts/${RELEASE_CHANNEL}-linux.yml
|
||||
echo "stagingPercentage: ${ROLLOUT_PCT}" >> apps/desktop/artifacts/${RELEASE_CHANNEL}-mac.yml
|
||||
echo "stagingPercentage: ${ROLLOUT_PCT}" >> "apps/desktop/artifacts/${RELEASE_CHANNEL}.yml"
|
||||
echo "stagingPercentage: ${ROLLOUT_PCT}" >> "apps/desktop/artifacts/${RELEASE_CHANNEL}-linux.yml"
|
||||
echo "stagingPercentage: ${ROLLOUT_PCT}" >> "apps/desktop/artifacts/${RELEASE_CHANNEL}-mac.yml"
|
||||
|
||||
- name: Publish artifacts to S3
|
||||
if: ${{ inputs.publish_type != 'Dry Run' }}
|
||||
@@ -179,7 +187,7 @@ jobs:
|
||||
AWS_S3_BUCKET_NAME: ${{ steps.retrieve-secrets.outputs.aws-electron-bucket-name }}
|
||||
working-directory: apps/desktop/artifacts
|
||||
run: |
|
||||
aws s3 cp ./ $AWS_S3_BUCKET_NAME/desktop/ \
|
||||
aws s3 cp ./ "$AWS_S3_BUCKET_NAME/desktop/" \
|
||||
--acl "public-read" \
|
||||
--recursive \
|
||||
--quiet
|
||||
@@ -214,6 +222,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Log in to Azure
|
||||
uses: bitwarden/gh-actions/azure-login@main
|
||||
@@ -241,14 +251,14 @@ jobs:
|
||||
|
||||
- name: Download artifacts
|
||||
working-directory: apps/desktop/dist
|
||||
run: wget https://github.com/bitwarden/clients/releases/download/${{ env._RELEASE_TAG }}/bitwarden_${{ env._PKG_VERSION }}_amd64.snap
|
||||
run: wget "https://github.com/bitwarden/clients/releases/download/$_RELEASE_TAG/bitwarden_$_PKG_VERSION_amd64.snap"
|
||||
|
||||
- name: Deploy to Snap Store
|
||||
if: ${{ inputs.publish_type != 'Dry Run' }}
|
||||
env:
|
||||
SNAPCRAFT_STORE_CREDENTIALS: ${{ steps.retrieve-secrets.outputs.snapcraft-store-token }}
|
||||
run: |
|
||||
snapcraft upload bitwarden_${{ env._PKG_VERSION }}_amd64.snap --release stable
|
||||
snapcraft upload "bitwarden_$_PKG_VERSION_amd64.snap" --release stable
|
||||
snapcraft logout
|
||||
working-directory: apps/desktop/dist
|
||||
|
||||
@@ -266,6 +276,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout Repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Print Environment
|
||||
run: |
|
||||
@@ -300,7 +312,7 @@ jobs:
|
||||
|
||||
- name: Download artifacts
|
||||
working-directory: apps/desktop/dist
|
||||
run: Invoke-WebRequest -Uri "https://github.com/bitwarden/clients/releases/download/${{ env._RELEASE_TAG }}/bitwarden.${{ env._PKG_VERSION }}.nupkg" -OutFile bitwarden.${{ env._PKG_VERSION }}.nupkg
|
||||
run: Invoke-WebRequest -Uri "https://github.com/bitwarden/clients/releases/download/$_RELEASE_TAG/bitwarden.$_PKG_VERSION.nupkg" -OutFile "bitwarden.$_PKG_VERSION.nupkg"
|
||||
|
||||
- name: Push to Chocolatey
|
||||
if: ${{ inputs.publish_type != 'Dry Run' }}
|
||||
@@ -321,6 +333,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Validate release notes for MAS
|
||||
if: inputs.mas_publish && (inputs.release_notes == '' || inputs.release_notes == null)
|
||||
@@ -331,7 +345,7 @@ jobs:
|
||||
|
||||
- name: Download MacOS App Store build number
|
||||
working-directory: apps/desktop
|
||||
run: wget https://github.com/bitwarden/clients/releases/download/${{ env._RELEASE_TAG }}/macos-build-number.json
|
||||
run: wget "https://github.com/bitwarden/clients/releases/download/$_RELEASE_TAG/macos-build-number.json"
|
||||
|
||||
- name: Setup Ruby and Install Fastlane
|
||||
uses: ruby/setup-ruby@ca041f971d66735f3e5ff1e21cc13e2d51e7e535 # v1.233.0
|
||||
@@ -365,12 +379,14 @@ jobs:
|
||||
env:
|
||||
APP_STORE_CONNECT_TEAM_ISSUER: ${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-TEAM-ISSUER }}
|
||||
APP_STORE_CONNECT_AUTH_KEY: ${{ steps.get-kv-secrets.outputs.APP-STORE-CONNECT-AUTH-KEY }}
|
||||
_RELEASE_NOTES: ${{ inputs.release_notes }}
|
||||
_PUBLISH_TYPE: ${{ inputs.publish_type }}
|
||||
working-directory: apps/desktop
|
||||
run: |
|
||||
BUILD_NUMBER=$(jq -r '.buildNumber' macos-build-number.json)
|
||||
CHANGELOG="${{ inputs.release_notes }}"
|
||||
IS_DRY_RUN="${{ inputs.publish_type == 'Dry Run' }}"
|
||||
|
||||
CHANGELOG="$_RELEASE_NOTES"
|
||||
IS_DRY_RUN="$_PUBLISH_TYPE == 'Dry Run'"
|
||||
|
||||
if [ "$IS_DRY_RUN" = "true" ]; then
|
||||
echo "🧪 DRY RUN MODE - Testing without actual App Store submission"
|
||||
echo "📦 Would publish build $BUILD_NUMBER to Mac App Store"
|
||||
@@ -388,10 +404,10 @@ jobs:
|
||||
fi
|
||||
|
||||
fastlane publish --verbose \
|
||||
app_version:"${{ env._PKG_VERSION }}" \
|
||||
build_number:$BUILD_NUMBER \
|
||||
app_version:"$PKG_VERSION" \
|
||||
build_number:"$BUILD_NUMBER" \
|
||||
changelog:"$CHANGELOG" \
|
||||
dry_run:$IS_DRY_RUN
|
||||
dry_run:"$IS_DRY_RUN"
|
||||
|
||||
update-deployment:
|
||||
name: Update Deployment Status
|
||||
|
||||
32
.github/workflows/publish-web.yml
vendored
32
.github/workflows/publish-web.yml
vendored
@@ -29,6 +29,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Branch check
|
||||
if: ${{ inputs.publish_type != 'Dry Run' }}
|
||||
@@ -73,6 +75,8 @@ jobs:
|
||||
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
########## ACR ##########
|
||||
- name: Log in to Azure
|
||||
@@ -100,33 +104,33 @@ jobs:
|
||||
- name: Pull branch image
|
||||
run: |
|
||||
if [[ "${{ inputs.publish_type }}" == "Dry Run" ]]; then
|
||||
docker pull $_AZ_REGISTRY/web:latest
|
||||
docker pull "$_AZ_REGISTRY/web:latest"
|
||||
else
|
||||
docker pull $_AZ_REGISTRY/web:$_BRANCH_NAME
|
||||
docker pull "$_AZ_REGISTRY/web:$_BRANCH_NAME"
|
||||
fi
|
||||
|
||||
- name: Tag version
|
||||
run: |
|
||||
if [[ "${{ inputs.publish_type }}" == "Dry Run" ]]; then
|
||||
docker tag $_AZ_REGISTRY/web:latest $_AZ_REGISTRY/web:dryrun
|
||||
docker tag $_AZ_REGISTRY/web:latest $_AZ_REGISTRY/web-sh:dryrun
|
||||
docker tag "$_AZ_REGISTRY/web:latest" "$_AZ_REGISTRY/web:dryrun"
|
||||
docker tag "$_AZ_REGISTRY/web:latest" "$_AZ_REGISTRY/web-sh:dryrun"
|
||||
else
|
||||
docker tag $_AZ_REGISTRY/web:$_BRANCH_NAME $_AZ_REGISTRY/web:$_RELEASE_VERSION
|
||||
docker tag $_AZ_REGISTRY/web:$_BRANCH_NAME $_AZ_REGISTRY/web-sh:$_RELEASE_VERSION
|
||||
docker tag $_AZ_REGISTRY/web:$_BRANCH_NAME $_AZ_REGISTRY/web:latest
|
||||
docker tag $_AZ_REGISTRY/web:$_BRANCH_NAME $_AZ_REGISTRY/web-sh:latest
|
||||
docker tag "$_AZ_REGISTRY/web:$_BRANCH_NAME" "$_AZ_REGISTRY/web:$_RELEASE_VERSION"
|
||||
docker tag "$_AZ_REGISTRY/web:$_BRANCH_NAME" "$_AZ_REGISTRY/web-sh:$_RELEASE_VERSION"
|
||||
docker tag "$_AZ_REGISTRY/web:$_BRANCH_NAME" "$_AZ_REGISTRY/web:latest"
|
||||
docker tag "$_AZ_REGISTRY/web:$_BRANCH_NAME" "$_AZ_REGISTRY/web-sh:latest"
|
||||
fi
|
||||
|
||||
- name: Push version
|
||||
run: |
|
||||
if [[ "${{ inputs.publish_type }}" == "Dry Run" ]]; then
|
||||
docker push $_AZ_REGISTRY/web:dryrun
|
||||
docker push $_AZ_REGISTRY/web-sh:dryrun
|
||||
docker push "$_AZ_REGISTRY/web:dryrun"
|
||||
docker push "$_AZ_REGISTRY/web-sh:dryrun"
|
||||
else
|
||||
docker push $_AZ_REGISTRY/web:$_RELEASE_VERSION
|
||||
docker push $_AZ_REGISTRY/web-sh:$_RELEASE_VERSION
|
||||
docker push $_AZ_REGISTRY/web:latest
|
||||
docker push $_AZ_REGISTRY/web-sh:latest
|
||||
docker push "$_AZ_REGISTRY/web:$_RELEASE_VERSION"
|
||||
docker push "$_AZ_REGISTRY/web-sh:$_RELEASE_VERSION"
|
||||
docker push "$_AZ_REGISTRY/web:latest"
|
||||
docker push "$_AZ_REGISTRY/web-sh:latest"
|
||||
fi
|
||||
|
||||
- name: Log out from Azure
|
||||
|
||||
22
.github/workflows/release-browser.yml
vendored
22
.github/workflows/release-browser.yml
vendored
@@ -29,6 +29,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Branch check
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||
@@ -60,6 +62,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Testing locales - extName length
|
||||
run: |
|
||||
@@ -69,9 +73,11 @@ jobs:
|
||||
echo "============"
|
||||
echo "extName string must be 40 characters or less"
|
||||
echo
|
||||
for locale in $(ls src/_locales/); do
|
||||
string_length=$(jq '.extName.message | length' src/_locales/$locale/messages.json)
|
||||
if [[ $string_length -gt 40 ]]; then
|
||||
|
||||
for locale_path in src/_locales/*/messages.json; do
|
||||
locale=$(basename "$(dirname "$locale_path")")
|
||||
string_length=$(jq '.extName.message | length' "$locale_path")
|
||||
if [ "$string_length" -gt 40 ]; then
|
||||
echo "$locale: $string_length"
|
||||
found_error=true
|
||||
fi
|
||||
@@ -126,11 +132,11 @@ jobs:
|
||||
env:
|
||||
PACKAGE_VERSION: ${{ needs.setup.outputs.release_version }}
|
||||
run: |
|
||||
mv browser-source.zip browser-source-$PACKAGE_VERSION.zip
|
||||
mv dist-chrome.zip dist-chrome-$PACKAGE_VERSION.zip
|
||||
mv dist-opera.zip dist-opera-$PACKAGE_VERSION.zip
|
||||
mv dist-firefox.zip dist-firefox-$PACKAGE_VERSION.zip
|
||||
mv dist-edge.zip dist-edge-$PACKAGE_VERSION.zip
|
||||
mv browser-source.zip "browser-source-$PACKAGE_VERSION.zip"
|
||||
mv dist-chrome.zip "dist-chrome-$PACKAGE_VERSION.zip"
|
||||
mv dist-opera.zip "dist-opera-$PACKAGE_VERSION.zip"
|
||||
mv dist-firefox.zip "dist-firefox-$PACKAGE_VERSION.zip"
|
||||
mv dist-edge.zip "dist-edge-$PACKAGE_VERSION.zip"
|
||||
|
||||
- name: Create release
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||
|
||||
2
.github/workflows/release-cli.yml
vendored
2
.github/workflows/release-cli.yml
vendored
@@ -30,6 +30,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Branch check
|
||||
if: ${{ inputs.release_type != 'Dry Run' }}
|
||||
|
||||
14
.github/workflows/release-desktop.yml
vendored
14
.github/workflows/release-desktop.yml
vendored
@@ -32,6 +32,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Branch check
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||
@@ -55,18 +57,20 @@ jobs:
|
||||
|
||||
- name: Get Version Channel
|
||||
id: release_channel
|
||||
env:
|
||||
_VERSION: ${{ steps.version.outputs.version }}
|
||||
run: |
|
||||
case "${{ steps.version.outputs.version }}" in
|
||||
case "$_VERSION" in
|
||||
*"alpha"*)
|
||||
echo "channel=alpha" >> $GITHUB_OUTPUT
|
||||
echo "channel=alpha" >> "$GITHUB_OUTPUT"
|
||||
echo "[!] We do not yet support 'alpha'"
|
||||
exit 1
|
||||
;;
|
||||
*"beta"*)
|
||||
echo "channel=beta" >> $GITHUB_OUTPUT
|
||||
echo "channel=beta" >> "$GITHUB_OUTPUT"
|
||||
;;
|
||||
*)
|
||||
echo "channel=latest" >> $GITHUB_OUTPUT
|
||||
echo "channel=latest" >> "$GITHUB_OUTPUT"
|
||||
;;
|
||||
esac
|
||||
|
||||
@@ -92,7 +96,7 @@ jobs:
|
||||
env:
|
||||
PKG_VERSION: ${{ steps.version.outputs.version }}
|
||||
working-directory: apps/desktop/artifacts
|
||||
run: mv Bitwarden-${{ env.PKG_VERSION }}-universal.pkg Bitwarden-${{ env.PKG_VERSION }}-universal.pkg.archive
|
||||
run: mv "Bitwarden-$PKG_VERSION-universal.pkg" "Bitwarden-$PKG_VERSION-universal.pkg.archive"
|
||||
|
||||
- name: Create Release
|
||||
uses: ncipollo/release-action@cdcc88a9acf3ca41c16c37bb7d21b9ad48560d87 # v1.15.0
|
||||
|
||||
8
.github/workflows/release-web.yml
vendored
8
.github/workflows/release-web.yml
vendored
@@ -26,6 +26,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Branch check
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||
@@ -79,9 +81,11 @@ jobs:
|
||||
|
||||
- name: Rename assets
|
||||
working-directory: apps/web/artifacts
|
||||
env:
|
||||
_RELEASE_VERSION: ${{ needs.setup.outputs.release_version }}
|
||||
run: |
|
||||
mv web-*-selfhosted-COMMERCIAL.zip web-${{ needs.setup.outputs.release_version }}-selfhosted-COMMERCIAL.zip
|
||||
mv web-*-selfhosted-open-source.zip web-${{ needs.setup.outputs.release_version }}-selfhosted-open-source.zip
|
||||
mv web-*-selfhosted-COMMERCIAL.zip "web-$_RELEASE_VERSION-selfhosted-COMMERCIAL.zip"
|
||||
mv web-*-selfhosted-open-source.zip "web-$_RELEASE_VERSION-selfhosted-open-source.zip"
|
||||
|
||||
- name: Create release
|
||||
if: ${{ github.event.inputs.release_type != 'Dry Run' }}
|
||||
|
||||
100
.github/workflows/repository-management.yml
vendored
100
.github/workflows/repository-management.yml
vendored
@@ -57,7 +57,7 @@ jobs:
|
||||
BRANCH="rc"
|
||||
fi
|
||||
|
||||
echo "branch=$BRANCH" >> $GITHUB_OUTPUT
|
||||
echo "branch=$BRANCH" >> "$GITHUB_OUTPUT"
|
||||
|
||||
bump_version:
|
||||
name: Bump Version
|
||||
@@ -108,6 +108,7 @@ jobs:
|
||||
with:
|
||||
ref: main
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
persist-credentials: true
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
@@ -124,7 +125,7 @@ jobs:
|
||||
id: current-browser-version
|
||||
run: |
|
||||
CURRENT_VERSION=$(cat package.json | jq -r '.version')
|
||||
echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "version=$CURRENT_VERSION" >> "$GITHUB_OUTPUT"
|
||||
working-directory: apps/browser
|
||||
|
||||
- name: Browser - Verify input version
|
||||
@@ -140,8 +141,7 @@ jobs:
|
||||
fi
|
||||
|
||||
# Check if version is newer.
|
||||
printf '%s\n' "${CURRENT_VERSION}" "${NEW_VERSION}" | sort -C -V
|
||||
if [ $? -eq 0 ]; then
|
||||
if printf '%s\n' "${CURRENT_VERSION}" "${NEW_VERSION}" | sort -C -V; then
|
||||
echo "Version check successful."
|
||||
else
|
||||
echo "Version check failed."
|
||||
@@ -161,14 +161,14 @@ jobs:
|
||||
id: bump-browser-version-override
|
||||
env:
|
||||
VERSION: ${{ inputs.version_number_override }}
|
||||
run: npm version --workspace=@bitwarden/browser $VERSION
|
||||
run: npm version --workspace=@bitwarden/browser "$VERSION"
|
||||
|
||||
- name: Bump Browser Version - Automatic Calculation
|
||||
if: ${{ inputs.bump_browser == true && inputs.version_number_override == '' }}
|
||||
id: bump-browser-version-automatic
|
||||
env:
|
||||
VERSION: ${{ steps.calculate-next-browser-version.outputs.version }}
|
||||
run: npm version --workspace=@bitwarden/browser $VERSION
|
||||
run: npm version --workspace=@bitwarden/browser "$VERSION"
|
||||
|
||||
- name: Bump Browser Version - Manifest - Version Override
|
||||
if: ${{ inputs.bump_browser == true && inputs.version_number_override != '' }}
|
||||
@@ -211,7 +211,7 @@ jobs:
|
||||
id: current-cli-version
|
||||
run: |
|
||||
CURRENT_VERSION=$(cat package.json | jq -r '.version')
|
||||
echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "version=$CURRENT_VERSION" >> "$GITHUB_OUTPUT"
|
||||
working-directory: apps/cli
|
||||
|
||||
- name: CLI - Verify input version
|
||||
@@ -227,8 +227,7 @@ jobs:
|
||||
fi
|
||||
|
||||
# Check if version is newer.
|
||||
printf '%s\n' "${CURRENT_VERSION}" "${NEW_VERSION}" | sort -C -V
|
||||
if [ $? -eq 0 ]; then
|
||||
if printf '%s\n' "${CURRENT_VERSION}" "${NEW_VERSION}" | sort -C -V; then
|
||||
echo "Version check successful."
|
||||
else
|
||||
echo "Version check failed."
|
||||
@@ -248,14 +247,14 @@ jobs:
|
||||
id: bump-cli-version-override
|
||||
env:
|
||||
VERSION: ${{ inputs.version_number_override }}
|
||||
run: npm version --workspace=@bitwarden/cli $VERSION
|
||||
run: npm version --workspace=@bitwarden/cli "$VERSION"
|
||||
|
||||
- name: Bump CLI Version - Automatic Calculation
|
||||
if: ${{ inputs.bump_cli == true && inputs.version_number_override == '' }}
|
||||
id: bump-cli-version-automatic
|
||||
env:
|
||||
VERSION: ${{ steps.calculate-next-cli-version.outputs.version }}
|
||||
run: npm version --workspace=@bitwarden/cli $VERSION
|
||||
run: npm version --workspace=@bitwarden/cli "$VERSION"
|
||||
|
||||
### Desktop
|
||||
- name: Get current Desktop version
|
||||
@@ -263,7 +262,7 @@ jobs:
|
||||
id: current-desktop-version
|
||||
run: |
|
||||
CURRENT_VERSION=$(cat package.json | jq -r '.version')
|
||||
echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "version=$CURRENT_VERSION" >> "$GITHUB_OUTPUT"
|
||||
working-directory: apps/desktop
|
||||
|
||||
- name: Desktop - Verify input version
|
||||
@@ -279,8 +278,7 @@ jobs:
|
||||
fi
|
||||
|
||||
# Check if version is newer.
|
||||
printf '%s\n' "${CURRENT_VERSION}" "${NEW_VERSION}" | sort -C -V
|
||||
if [ $? -eq 0 ]; then
|
||||
if printf '%s\n' "${CURRENT_VERSION}" "${NEW_VERSION}" | sort -C -V; then
|
||||
echo "Version check successful."
|
||||
else
|
||||
echo "Version check failed."
|
||||
@@ -300,27 +298,27 @@ jobs:
|
||||
id: bump-desktop-version-override
|
||||
env:
|
||||
VERSION: ${{ inputs.version_number_override }}
|
||||
run: npm version --workspace=@bitwarden/desktop $VERSION
|
||||
run: npm version --workspace=@bitwarden/desktop "$VERSION"
|
||||
|
||||
- name: Bump Desktop Version - Root - Automatic Calculation
|
||||
if: ${{ inputs.bump_desktop == true && inputs.version_number_override == '' }}
|
||||
id: bump-desktop-version-automatic
|
||||
env:
|
||||
VERSION: ${{ steps.calculate-next-desktop-version.outputs.version }}
|
||||
run: npm version --workspace=@bitwarden/desktop $VERSION
|
||||
run: npm version --workspace=@bitwarden/desktop "$VERSION"
|
||||
|
||||
- name: Bump Desktop Version - App - Version Override
|
||||
if: ${{ inputs.bump_desktop == true && inputs.version_number_override != '' }}
|
||||
env:
|
||||
VERSION: ${{ inputs.version_number_override }}
|
||||
run: npm version $VERSION
|
||||
run: npm version "$VERSION"
|
||||
working-directory: "apps/desktop/src"
|
||||
|
||||
- name: Bump Desktop Version - App - Automatic Calculation
|
||||
if: ${{ inputs.bump_desktop == true && inputs.version_number_override == '' }}
|
||||
env:
|
||||
VERSION: ${{ steps.calculate-next-desktop-version.outputs.version }}
|
||||
run: npm version $VERSION
|
||||
run: npm version "$VERSION"
|
||||
working-directory: "apps/desktop/src"
|
||||
|
||||
### Web
|
||||
@@ -329,7 +327,7 @@ jobs:
|
||||
id: current-web-version
|
||||
run: |
|
||||
CURRENT_VERSION=$(cat package.json | jq -r '.version')
|
||||
echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "version=$CURRENT_VERSION" >> "$GITHUB_OUTPUT"
|
||||
working-directory: apps/web
|
||||
|
||||
- name: Web - Verify input version
|
||||
@@ -345,8 +343,7 @@ jobs:
|
||||
fi
|
||||
|
||||
# Check if version is newer.
|
||||
printf '%s\n' "${CURRENT_VERSION}" "${NEW_VERSION}" | sort -C -V
|
||||
if [ $? -eq 0 ]; then
|
||||
if printf '%s\n' "${CURRENT_VERSION}" "${NEW_VERSION}" | sort -C -V; then
|
||||
echo "Version check successful."
|
||||
else
|
||||
echo "Version check failed."
|
||||
@@ -366,14 +363,14 @@ jobs:
|
||||
id: bump-web-version-override
|
||||
env:
|
||||
VERSION: ${{ inputs.version_number_override }}
|
||||
run: npm version --workspace=@bitwarden/web-vault $VERSION
|
||||
run: npm version --workspace=@bitwarden/web-vault "$VERSION"
|
||||
|
||||
- name: Bump Web Version - Automatic Calculation
|
||||
if: ${{ inputs.bump_web == true && inputs.version_number_override == '' }}
|
||||
id: bump-web-version-automatic
|
||||
env:
|
||||
VERSION: ${{ steps.calculate-next-web-version.outputs.version }}
|
||||
run: npm version --workspace=@bitwarden/web-vault $VERSION
|
||||
run: npm version --workspace=@bitwarden/web-vault "$VERSION"
|
||||
|
||||
########################
|
||||
|
||||
@@ -381,38 +378,50 @@ jobs:
|
||||
id: set-final-version-output
|
||||
env:
|
||||
VERSION: ${{ inputs.version_number_override }}
|
||||
_BUMP_BROWSER_VERSION_OVERRIDE_OUTCOME: ${{ steps.bump-browser-version-override.outcome }}
|
||||
_BUMP_BROWSER_VERSION_AUTOMATIC_OUTCOME: ${{ steps.bump-browser-version-automatic.outcome }}
|
||||
_CALCULATE_NEXT_BROWSER_VERSION: ${{ steps.calculate-next-browser-version.outputs.version }}
|
||||
_BUMP_CLI_VERSION_OVERRIDE_OUTCOME: ${{ steps.bump-cli-version-override.outcome }}
|
||||
_BUMP_CLI_VERSION_AUTOMATIC_OUTCOME: ${{ steps.bump-cli-version-automatic.outcome }}
|
||||
_CALCULATE_NEXT_CLI_VERSION: ${{ steps.calculate-next-cli-version.outputs.version }}
|
||||
_BUMP_DESKTOP_VERSION_OVERRIDE_OUTCOME: ${{ steps.bump-desktop-version-override.outcome }}
|
||||
_BUMP_DESKTOP_VERSION_AUTOMATIC_OUTCOME: ${{ steps.bump-desktop-version-automatic.outcome }}
|
||||
_CALCULATE_NEXT_DESKTOP_VERSION: ${{ steps.calculate-next-desktop-version.outputs.version }}
|
||||
_BUMP_WEB_VERSION_OVERRIDE_OUTCOME: ${{ steps.bump-web-version-override.outcome }}
|
||||
_BUMP_WEB_VERSION_AUTOMATIC_OUTCOME: ${{ steps.bump-web-version-automatic.outcome }}
|
||||
_CALCULATE_NEXT_WEB_VERSION: ${{ steps.calculate-next-web-version.outputs.version }}
|
||||
run: |
|
||||
if [[ "${{ steps.bump-browser-version-override.outcome }}" = "success" ]]; then
|
||||
echo "version_browser=$VERSION" >> $GITHUB_OUTPUT
|
||||
elif [[ "${{ steps.bump-browser-version-automatic.outcome }}" = "success" ]]; then
|
||||
echo "version_browser=${{ steps.calculate-next-browser-version.outputs.version }}" >> $GITHUB_OUTPUT
|
||||
if [[ "$_BUMP_BROWSER_VERSION_OVERRIDE_OUTCOME" = "success" ]]; then
|
||||
echo "version_browser=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
elif [[ "$_BUMP_BROWSER_VERSION_AUTOMATIC_OUTCOME" = "success" ]]; then
|
||||
echo "version_browser=$_CALCULATE_NEXT_BROWSER_VERSION" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
if [[ "${{ steps.bump-cli-version-override.outcome }}" = "success" ]]; then
|
||||
echo "version_cli=$VERSION" >> $GITHUB_OUTPUT
|
||||
elif [[ "${{ steps.bump-cli-version-automatic.outcome }}" = "success" ]]; then
|
||||
echo "version_cli=${{ steps.calculate-next-cli-version.outputs.version }}" >> $GITHUB_OUTPUT
|
||||
if [[ "$_BUMP_CLI_VERSION_OVERRIDE_OUTCOME" = "success" ]]; then
|
||||
echo "version_cli=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
elif [[ "$_BUMP_CLI_VERSION_AUTOMATIC_OUTCOME" = "success" ]]; then
|
||||
echo "version_cli=$_CALCULATE_NEXT_CLI_VERSION" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
if [[ "${{ steps.bump-desktop-version-override.outcome }}" = "success" ]]; then
|
||||
echo "version_desktop=$VERSION" >> $GITHUB_OUTPUT
|
||||
elif [[ "${{ steps.bump-desktop-version-automatic.outcome }}" = "success" ]]; then
|
||||
echo "version_desktop=${{ steps.calculate-next-desktop-version.outputs.version }}" >> $GITHUB_OUTPUT
|
||||
if [[ "$_BUMP_DESKTOP_VERSION_OVERRIDE_OUTCOME" = "success" ]]; then
|
||||
echo "version_desktop=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
elif [[ "$_BUMP_DESKTOP_VERSION_AUTOMATIC_OUTCOME" = "success" ]]; then
|
||||
echo "version_desktop=$_CALCULATE_NEXT_DESKTOP_VERSION" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
if [[ "${{ steps.bump-web-version-override.outcome }}" = "success" ]]; then
|
||||
echo "version_web=$VERSION" >> $GITHUB_OUTPUT
|
||||
elif [[ "${{ steps.bump-web-version-automatic.outcome }}" = "success" ]]; then
|
||||
echo "version_web=${{ steps.calculate-next-web-version.outputs.version }}" >> $GITHUB_OUTPUT
|
||||
if [[ "$_BUMP_WEB_VERSION_OVERRIDE_OUTCOME" = "success" ]]; then
|
||||
echo "version_web=$VERSION" >> "$GITHUB_OUTPUT"
|
||||
elif [[ "$_BUMP_WEB_VERSION_AUTOMATIC_OUTCOME" = "success" ]]; then
|
||||
echo "version_web=$_CALCULATE_NEXT_WEB_VERSION" >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
- name: Check if version changed
|
||||
id: version-changed
|
||||
run: |
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
echo "changes_to_commit=TRUE" >> $GITHUB_OUTPUT
|
||||
echo "changes_to_commit=TRUE" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "changes_to_commit=FALSE" >> $GITHUB_OUTPUT
|
||||
echo "changes_to_commit=FALSE" >> "$GITHUB_OUTPUT"
|
||||
echo "No changes to commit!";
|
||||
fi
|
||||
|
||||
@@ -464,13 +473,14 @@ jobs:
|
||||
with:
|
||||
ref: ${{ inputs.target_ref }}
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
persist-credentials: true
|
||||
|
||||
- name: Check if ${{ needs.setup.outputs.branch }} branch exists
|
||||
env:
|
||||
BRANCH_NAME: ${{ needs.setup.outputs.branch }}
|
||||
run: |
|
||||
if [[ $(git ls-remote --heads origin $BRANCH_NAME) ]]; then
|
||||
echo "$BRANCH_NAME already exists! Please delete $BRANCH_NAME before running again." >> $GITHUB_STEP_SUMMARY
|
||||
if [[ $(git ls-remote --heads origin "$BRANCH_NAME") ]]; then
|
||||
echo "$BRANCH_NAME already exists! Please delete $BRANCH_NAME before running again." >> "$GITHUB_STEP_SUMMARY"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -478,5 +488,5 @@ jobs:
|
||||
env:
|
||||
BRANCH_NAME: ${{ needs.setup.outputs.branch }}
|
||||
run: |
|
||||
git switch --quiet --create $BRANCH_NAME
|
||||
git push --quiet --set-upstream origin $BRANCH_NAME
|
||||
git switch --quiet --create "$BRANCH_NAME"
|
||||
git push --quiet --set-upstream origin "$BRANCH_NAME"
|
||||
|
||||
@@ -39,10 +39,10 @@ jobs:
|
||||
AWS_SECRET_ACCESS_KEY: ${{ steps.retrieve-secrets.outputs.aws-electron-access-key }}
|
||||
AWS_DEFAULT_REGION: 'us-west-2'
|
||||
AWS_S3_BUCKET_NAME: ${{ steps.retrieve-secrets.outputs.aws-electron-bucket-name }}
|
||||
run: aws s3 cp $AWS_S3_BUCKET_NAME/desktop/latest.yml . --quiet
|
||||
run: aws s3 cp "$AWS_S3_BUCKET_NAME/desktop/latest.yml" . --quiet
|
||||
|
||||
- name: Get current rollout percentage
|
||||
run: |
|
||||
CURRENT_PCT=$(sed -r -n "s/stagingPercentage:\s([0-9]+)/\1/p" latest.yml)
|
||||
CURRENT_VERSION=$(sed -r -n "s/version:\s(.*)/\1/p" latest.yml)
|
||||
echo "Desktop ${CURRENT_VERSION} rollout percentage is ${CURRENT_PCT}%" >> $GITHUB_STEP_SUMMARY
|
||||
echo "Desktop ${CURRENT_VERSION} rollout percentage is ${CURRENT_PCT}%" >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
12
.github/workflows/staged-rollout-desktop.yml
vendored
12
.github/workflows/staged-rollout-desktop.yml
vendored
@@ -47,11 +47,11 @@ jobs:
|
||||
AWS_DEFAULT_REGION: 'us-west-2'
|
||||
AWS_S3_BUCKET_NAME: ${{ steps.retrieve-secrets.outputs.aws-electron-bucket-name }}
|
||||
run: |
|
||||
aws s3 cp $AWS_S3_BUCKET_NAME/desktop/latest.yml . \
|
||||
aws s3 cp "$AWS_S3_BUCKET_NAME/desktop/latest.yml" . \
|
||||
--quiet
|
||||
aws s3 cp $AWS_S3_BUCKET_NAME/desktop/latest-linux.yml . \
|
||||
aws s3 cp "$AWS_S3_BUCKET_NAME/desktop/latest-linux.yml" . \
|
||||
--quiet
|
||||
aws s3 cp $AWS_S3_BUCKET_NAME/desktop/latest-mac.yml . \
|
||||
aws s3 cp "$AWS_S3_BUCKET_NAME/desktop/latest-mac.yml" . \
|
||||
--quiet
|
||||
|
||||
- name: Check new rollout percentage
|
||||
@@ -86,11 +86,11 @@ jobs:
|
||||
AWS_DEFAULT_REGION: 'us-west-2'
|
||||
AWS_S3_BUCKET_NAME: ${{ steps.retrieve-secrets.outputs.aws-electron-bucket-name }}
|
||||
run: |
|
||||
aws s3 cp latest.yml $AWS_S3_BUCKET_NAME/desktop/ \
|
||||
aws s3 cp latest.yml "$AWS_S3_BUCKET_NAME/desktop/" \
|
||||
--acl "public-read"
|
||||
|
||||
aws s3 cp latest-linux.yml $AWS_S3_BUCKET_NAME/desktop/ \
|
||||
aws s3 cp latest-linux.yml "$AWS_S3_BUCKET_NAME/desktop/" \
|
||||
--acl "public-read"
|
||||
|
||||
aws s3 cp latest-mac.yml $AWS_S3_BUCKET_NAME/desktop/ \
|
||||
aws s3 cp latest-mac.yml "$AWS_S3_BUCKET_NAME/desktop/" \
|
||||
--acl "public-read"
|
||||
|
||||
@@ -21,6 +21,7 @@ jobs:
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
|
||||
- name: Check for job requirements
|
||||
if: ${{ !github.event.workflow_run.pull_requests || !github.event.workflow_run.head_branch }}
|
||||
|
||||
10
.github/workflows/test.yml
vendored
10
.github/workflows/test.yml
vendored
@@ -25,13 +25,15 @@ jobs:
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- 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
|
||||
echo "node_version=$NODE_VERSION" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5.0.0
|
||||
@@ -102,6 +104,8 @@ jobs:
|
||||
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Build
|
||||
working-directory: ./apps/desktop/desktop_native
|
||||
@@ -134,6 +138,8 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install rust
|
||||
uses: dtolnay/rust-toolchain@b3b07ba8b418998c39fb20f53e8b695cdcc8de1b # stable
|
||||
@@ -168,6 +174,8 @@ jobs:
|
||||
steps:
|
||||
- name: Check out repo
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Download jest coverage
|
||||
uses: actions/download-artifact@634f93cb2916e3fdff6788551b99b062d0335ce0 # v5.0.0
|
||||
|
||||
7
.github/workflows/version-auto-bump.yml
vendored
7
.github/workflows/version-auto-bump.yml
vendored
@@ -42,6 +42,7 @@ jobs:
|
||||
with:
|
||||
ref: main
|
||||
token: ${{ steps.app-token.outputs.token }}
|
||||
persist-credentials: true
|
||||
|
||||
- name: Configure Git
|
||||
run: |
|
||||
@@ -52,7 +53,7 @@ jobs:
|
||||
id: current-desktop-version
|
||||
run: |
|
||||
CURRENT_VERSION=$(cat package.json | jq -r '.version')
|
||||
echo "version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "version=$CURRENT_VERSION" >> "$GITHUB_OUTPUT"
|
||||
working-directory: apps/desktop
|
||||
|
||||
- name: Calculate next Desktop release version
|
||||
@@ -65,12 +66,12 @@ jobs:
|
||||
id: bump-desktop-version-automatic
|
||||
env:
|
||||
VERSION: ${{ steps.calculate-next-desktop-version.outputs.version }}
|
||||
run: npm version --workspace=@bitwarden/desktop $VERSION
|
||||
run: npm version --workspace=@bitwarden/desktop "$VERSION"
|
||||
|
||||
- name: Bump Desktop Version - App - Automatic Calculation
|
||||
env:
|
||||
VERSION: ${{ steps.calculate-next-desktop-version.outputs.version }}
|
||||
run: npm version $VERSION
|
||||
run: npm version "$VERSION"
|
||||
working-directory: "apps/desktop/src"
|
||||
|
||||
- name: Commit files
|
||||
|
||||
@@ -300,6 +300,7 @@ import { BrowserActionsService } from "../platform/actions/browser-actions.servi
|
||||
import { DefaultBadgeBrowserApi } from "../platform/badge/badge-browser-api";
|
||||
import { BadgeService } from "../platform/badge/badge.service";
|
||||
import { BrowserApi } from "../platform/browser/browser-api";
|
||||
import BrowserPopupUtils from "../platform/browser/browser-popup-utils";
|
||||
import { flagEnabled } from "../platform/flags";
|
||||
import { IpcBackgroundService } from "../platform/ipc/ipc-background.service";
|
||||
import { IpcContentScriptManagerService } from "../platform/ipc/ipc-content-script-manager.service";
|
||||
@@ -1237,6 +1238,12 @@ export default class MainBackground {
|
||||
|
||||
const systemUtilsServiceReloadCallback = async () => {
|
||||
await this.taskSchedulerService.clearAllScheduledTasks();
|
||||
|
||||
// Close browser action popup before reloading to prevent zombie popup with invalidated context.
|
||||
// The 'reloadProcess' message is sent by ProcessReloadService before this callback runs,
|
||||
// and popups will close themselves upon receiving it. Poll to verify popup is actually closed.
|
||||
await BrowserPopupUtils.waitForAllPopupsClose();
|
||||
|
||||
BrowserApi.reloadExtension();
|
||||
};
|
||||
|
||||
|
||||
@@ -337,6 +337,68 @@ describe("BrowserPopupUtils", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("waitForAllPopupsClose", () => {
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it("should resolve immediately if no popups are open", async () => {
|
||||
jest.spyOn(BrowserApi, "isPopupOpen").mockResolvedValue(false);
|
||||
|
||||
const promise = BrowserPopupUtils.waitForAllPopupsClose();
|
||||
jest.advanceTimersByTime(100);
|
||||
|
||||
await expect(promise).resolves.toBeUndefined();
|
||||
expect(BrowserApi.isPopupOpen).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("should resolve after timeout if popup never closes when using custom timeout", async () => {
|
||||
jest.spyOn(BrowserApi, "isPopupOpen").mockResolvedValue(true);
|
||||
|
||||
const promise = BrowserPopupUtils.waitForAllPopupsClose(500);
|
||||
|
||||
// Advance past the timeout
|
||||
jest.advanceTimersByTime(600);
|
||||
|
||||
await expect(promise).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it("should resolve after timeout if popup never closes when using default timeout", async () => {
|
||||
jest.spyOn(BrowserApi, "isPopupOpen").mockResolvedValue(true);
|
||||
|
||||
const promise = BrowserPopupUtils.waitForAllPopupsClose();
|
||||
|
||||
// Advance past the default timeout
|
||||
jest.advanceTimersByTime(1100);
|
||||
|
||||
await expect(promise).resolves.toBeUndefined();
|
||||
});
|
||||
|
||||
it("should stop polling after popup closes before timeout", async () => {
|
||||
let callCount = 0;
|
||||
jest.spyOn(BrowserApi, "isPopupOpen").mockImplementation(async () => {
|
||||
callCount++;
|
||||
return callCount <= 2;
|
||||
});
|
||||
|
||||
const promise = BrowserPopupUtils.waitForAllPopupsClose(1000);
|
||||
|
||||
// Advance to when popup closes (300ms)
|
||||
jest.advanceTimersByTime(300);
|
||||
|
||||
await expect(promise).resolves.toBeUndefined();
|
||||
|
||||
// Advance further to ensure no more calls are made
|
||||
jest.advanceTimersByTime(1000);
|
||||
|
||||
expect(BrowserApi.isPopupOpen).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe("isSingleActionPopoutOpen", () => {
|
||||
const windowOptions = {
|
||||
id: 1,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// FIXME: Update this file to be type safe and remove this and next line
|
||||
// @ts-strict-ignore
|
||||
import { filter, firstValueFrom, interval, of, switchMap, takeWhile, timeout } from "rxjs";
|
||||
|
||||
import { ScrollOptions } from "./abstractions/browser-popup-utils.abstractions";
|
||||
import { BrowserApi } from "./browser-api";
|
||||
@@ -212,6 +213,27 @@ export default class BrowserPopupUtils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for all browser action popups to close, polling up to the specified timeout.
|
||||
* Used before extension reload to prevent zombie popups with invalidated contexts.
|
||||
*
|
||||
* @param timeoutMs - Maximum time to wait in milliseconds. Defaults to 1 second.
|
||||
* @returns Promise that resolves when all popups are closed or timeout is reached.
|
||||
*/
|
||||
static async waitForAllPopupsClose(timeoutMs = 1000): Promise<void> {
|
||||
await firstValueFrom(
|
||||
interval(100).pipe(
|
||||
switchMap(() => BrowserApi.isPopupOpen()),
|
||||
takeWhile((isOpen) => isOpen, true),
|
||||
filter((isOpen) => !isOpen),
|
||||
timeout({
|
||||
first: timeoutMs,
|
||||
with: () => of(true),
|
||||
}),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Identifies if a single action window is open based on the passed popoutKey.
|
||||
* Will focus the existing window, and close any other windows that might exist
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "popup-footer",
|
||||
templateUrl: "popup-footer.component.html",
|
||||
|
||||
@@ -16,6 +16,8 @@ import { PopupRouterCacheService } from "../view-cache/popup-router-cache.servic
|
||||
|
||||
import { PopupPageComponent } from "./popup-page.component";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "popup-header",
|
||||
templateUrl: "popup-header.component.html",
|
||||
@@ -23,13 +25,19 @@ import { PopupPageComponent } from "./popup-page.component";
|
||||
})
|
||||
export class PopupHeaderComponent {
|
||||
private popupRouterCacheService = inject(PopupRouterCacheService);
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
protected pageContentScrolled: Signal<boolean> = inject(PopupPageComponent).isScrolled;
|
||||
|
||||
/** Background color */
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input()
|
||||
background: "default" | "alt" = "default";
|
||||
|
||||
/** Display the back button, which uses Location.back() to go back one page in history */
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input()
|
||||
get showBackButton() {
|
||||
return this._showBackButton;
|
||||
@@ -41,6 +49,8 @@ export class PopupHeaderComponent {
|
||||
private _showBackButton = false;
|
||||
|
||||
/** Title string that will be inserted as an h1 */
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input({ required: true }) pageTitle: string;
|
||||
|
||||
/**
|
||||
@@ -48,6 +58,8 @@ export class PopupHeaderComponent {
|
||||
*
|
||||
* If unset, will call `location.back()`
|
||||
**/
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input()
|
||||
backAction: FunctionReturningAwaitable = async () => {
|
||||
return this.popupRouterCacheService.back();
|
||||
|
||||
@@ -41,6 +41,8 @@ import { PopupHeaderComponent } from "./popup-header.component";
|
||||
import { PopupPageComponent } from "./popup-page.component";
|
||||
import { PopupTabNavigationComponent } from "./popup-tab-navigation.component";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "extension-container",
|
||||
template: `
|
||||
@@ -51,6 +53,8 @@ import { PopupTabNavigationComponent } from "./popup-tab-navigation.component";
|
||||
})
|
||||
class ExtensionContainerComponent {}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "extension-popped-container",
|
||||
template: `
|
||||
@@ -62,6 +66,8 @@ class ExtensionContainerComponent {}
|
||||
})
|
||||
class ExtensionPoppedContainerComponent {}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "vault-placeholder",
|
||||
template: /*html*/ `
|
||||
@@ -95,6 +101,8 @@ class VaultComponent {
|
||||
protected data = Array.from(Array(20).keys());
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "mock-add-button",
|
||||
template: `
|
||||
@@ -107,6 +115,8 @@ class VaultComponent {
|
||||
})
|
||||
class MockAddButtonComponent {}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "mock-popout-button",
|
||||
template: `
|
||||
@@ -116,6 +126,8 @@ class MockAddButtonComponent {}
|
||||
})
|
||||
class MockPopoutButtonComponent {}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "mock-current-account",
|
||||
template: `
|
||||
@@ -127,6 +139,8 @@ class MockPopoutButtonComponent {}
|
||||
})
|
||||
class MockCurrentAccountComponent {}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "mock-search",
|
||||
template: ` <bit-search placeholder="Search"> </bit-search> `,
|
||||
@@ -134,6 +148,8 @@ class MockCurrentAccountComponent {}
|
||||
})
|
||||
class MockSearchComponent {}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "mock-banner",
|
||||
template: `
|
||||
@@ -145,6 +161,8 @@ class MockSearchComponent {}
|
||||
})
|
||||
class MockBannerComponent {}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "mock-vault-page",
|
||||
template: `
|
||||
@@ -172,6 +190,8 @@ class MockBannerComponent {}
|
||||
})
|
||||
class MockVaultPageComponent {}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "mock-vault-page-popped",
|
||||
template: `
|
||||
@@ -195,6 +215,8 @@ class MockVaultPageComponent {}
|
||||
})
|
||||
class MockVaultPagePoppedComponent {}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "mock-generator-page",
|
||||
template: `
|
||||
@@ -219,6 +241,8 @@ class MockVaultPagePoppedComponent {}
|
||||
})
|
||||
class MockGeneratorPageComponent {}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "mock-send-page",
|
||||
template: `
|
||||
@@ -243,6 +267,8 @@ class MockGeneratorPageComponent {}
|
||||
})
|
||||
class MockSendPageComponent {}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "mock-settings-page",
|
||||
template: `
|
||||
@@ -267,6 +293,8 @@ class MockSendPageComponent {}
|
||||
})
|
||||
class MockSettingsPageComponent {}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "mock-vault-subpage",
|
||||
template: `
|
||||
|
||||
@@ -4,6 +4,8 @@ import { booleanAttribute, Component, inject, Input, signal } from "@angular/cor
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { ScrollLayoutHostDirective } from "@bitwarden/components";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "popup-page",
|
||||
templateUrl: "popup-page.component.html",
|
||||
@@ -15,15 +17,23 @@ import { ScrollLayoutHostDirective } from "@bitwarden/components";
|
||||
export class PopupPageComponent {
|
||||
protected i18nService = inject(I18nService);
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input() loading = false;
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input({ transform: booleanAttribute })
|
||||
disablePadding = false;
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
protected scrolled = signal(false);
|
||||
isScrolled = this.scrolled.asReadonly();
|
||||
|
||||
/** Accessible loading label for the spinner. Defaults to "loading" */
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input() loadingText?: string = this.i18nService.t("loading");
|
||||
|
||||
handleScroll(event: Event) {
|
||||
|
||||
@@ -15,6 +15,8 @@ export type NavButton = {
|
||||
showBerry?: boolean;
|
||||
};
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "popup-tab-navigation",
|
||||
templateUrl: "popup-tab-navigation.component.html",
|
||||
@@ -24,6 +26,8 @@ export type NavButton = {
|
||||
},
|
||||
})
|
||||
export class PopupTabNavigationComponent {
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input() navButtons: NavButton[] = [];
|
||||
|
||||
constructor(private i18nService: I18nService) {}
|
||||
|
||||
@@ -36,6 +36,7 @@ import {
|
||||
LogoutReason,
|
||||
UserDecryptionOptionsServiceAbstraction,
|
||||
} from "@bitwarden/auth/common";
|
||||
import { BrowserApi } from "@bitwarden/browser/platform/browser/browser-api";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { AuthRequestAnsweringServiceAbstraction } from "@bitwarden/common/auth/abstractions/auth-request-answering/auth-request-answering.service.abstraction";
|
||||
import { AuthService } from "@bitwarden/common/auth/abstractions/auth.service";
|
||||
@@ -58,6 +59,7 @@ import {
|
||||
} from "@bitwarden/components";
|
||||
import { BiometricsService, BiometricStateService, KeyService } from "@bitwarden/key-management";
|
||||
|
||||
import BrowserPopupUtils from "../platform/browser/browser-popup-utils";
|
||||
import { PopupCompactModeService } from "../platform/popup/layout/popup-compact-mode.service";
|
||||
import { PopupSizeService } from "../platform/popup/layout/popup-size.service";
|
||||
import { initPopupClosedListener } from "../platform/services/popup-view-cache-background.service";
|
||||
@@ -286,6 +288,13 @@ export class AppComponent implements OnInit, OnDestroy {
|
||||
await this.biometricStateService.updateLastProcessReload();
|
||||
window.location.reload();
|
||||
}, 2000);
|
||||
} else {
|
||||
// Close browser action popup before extension reload to prevent zombie popup with invalidated context.
|
||||
// This issue occurs in Chromium-based browsers (Chrome, Vivaldi, etc.) where chrome.runtime.reload()
|
||||
// invalidates extension contexts before popup can close naturally
|
||||
if (BrowserPopupUtils.inPopup(window)) {
|
||||
BrowserApi.closePopup(window);
|
||||
}
|
||||
}
|
||||
} else if (msg.command === "reloadPopup") {
|
||||
// FIXME: Verify that this floating promise is intentional. If it is, add an explanatory comment and ensure there is proper error handling.
|
||||
|
||||
@@ -29,6 +29,8 @@ export interface ExtensionAnonLayoutWrapperData extends AnonLayoutWrapperData {
|
||||
hideFooter?: boolean;
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
templateUrl: "extension-anon-layout-wrapper.component.html",
|
||||
imports: [
|
||||
|
||||
@@ -164,6 +164,8 @@ type Story = StoryObj<ExtensionAnonLayoutWrapperComponent>;
|
||||
|
||||
// Default Example
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-default-primary-outlet-example-component",
|
||||
template: "<p>Primary Outlet Example: <br> your primary component goes here</p>",
|
||||
@@ -171,6 +173,8 @@ type Story = StoryObj<ExtensionAnonLayoutWrapperComponent>;
|
||||
})
|
||||
class DefaultPrimaryOutletExampleComponent {}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-default-secondary-outlet-example-component",
|
||||
template: "<p>Secondary Outlet Example: <br> your secondary component goes here</p>",
|
||||
@@ -178,6 +182,8 @@ class DefaultPrimaryOutletExampleComponent {}
|
||||
})
|
||||
class DefaultSecondaryOutletExampleComponent {}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-default-env-selector-outlet-example-component",
|
||||
template: "<p>Env Selector Outlet Example: <br> your env selector component goes here</p>",
|
||||
@@ -261,6 +267,8 @@ const changedData: ExtensionAnonLayoutWrapperData = {
|
||||
showLogo: false,
|
||||
};
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-dynamic-content-example-component",
|
||||
template: `
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<button
|
||||
type="button"
|
||||
class="tw-py-1.5 tw-px-4 tw-flex tw-gap-2 tw-items-center tw-size-full focus-visible:tw-ring-2 focus-visible:tw-ring-offset-0 focus:tw-outline-none focus-visible:tw-outline-none focus-visible:tw-ring-text-alt2 focus-visible:tw-z-10 tw-font-semibold tw-rounded-full tw-transition tw-border tw-border-solid tw-text-left tw-bg-primary-100 tw-text-primary-600 tw-border-primary-600 hover:tw-bg-hover-default hover:tw-text-primary-700 hover:tw-border-primary-700"
|
||||
(click)="openUpgradeDialog()"
|
||||
(click)="upgrade()"
|
||||
>
|
||||
<i class="bwi bwi-premium" aria-hidden="true"></i>
|
||||
{{ "upgradeYourPlan" | i18n }}
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
import { ComponentFixture, TestBed } from "@angular/core/testing";
|
||||
import { Router } from "@angular/router";
|
||||
import { mock, MockProxy } from "jest-mock-extended";
|
||||
import { BehaviorSubject, of } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { Account, AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { DialogRef, DialogService } from "@bitwarden/components";
|
||||
|
||||
import {
|
||||
UnifiedUpgradeDialogResult,
|
||||
UnifiedUpgradeDialogStatus,
|
||||
} from "../../unified-upgrade-dialog/unified-upgrade-dialog.component";
|
||||
|
||||
import { UpgradeNavButtonComponent } from "./upgrade-nav-button.component";
|
||||
|
||||
describe("UpgradeNavButtonComponent", () => {
|
||||
let component: UpgradeNavButtonComponent;
|
||||
let fixture: ComponentFixture<UpgradeNavButtonComponent>;
|
||||
let mockDialogService: MockProxy<DialogService>;
|
||||
let mockAccountService: MockProxy<AccountService>;
|
||||
let mockSyncService: MockProxy<SyncService>;
|
||||
let mockApiService: MockProxy<ApiService>;
|
||||
let mockRouter: MockProxy<Router>;
|
||||
let mockI18nService: MockProxy<I18nService>;
|
||||
let mockPlatformUtilsService: MockProxy<PlatformUtilsService>;
|
||||
let activeAccount$: BehaviorSubject<Account | null>;
|
||||
|
||||
const mockAccount: Account = {
|
||||
id: "user-id" as UserId,
|
||||
email: "test@example.com",
|
||||
emailVerified: true,
|
||||
name: "Test User",
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
mockDialogService = mock<DialogService>();
|
||||
mockAccountService = mock<AccountService>();
|
||||
mockSyncService = mock<SyncService>();
|
||||
mockApiService = mock<ApiService>();
|
||||
mockRouter = mock<Router>();
|
||||
mockI18nService = mock<I18nService>();
|
||||
mockPlatformUtilsService = mock<PlatformUtilsService>();
|
||||
|
||||
activeAccount$ = new BehaviorSubject<Account | null>(mockAccount);
|
||||
mockAccountService.activeAccount$ = activeAccount$;
|
||||
mockI18nService.t.mockImplementation((key) => key);
|
||||
mockPlatformUtilsService.isSelfHost.mockReturnValue(false);
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [UpgradeNavButtonComponent],
|
||||
providers: [
|
||||
{ provide: DialogService, useValue: mockDialogService },
|
||||
{ provide: AccountService, useValue: mockAccountService },
|
||||
{ provide: SyncService, useValue: mockSyncService },
|
||||
{ provide: ApiService, useValue: mockApiService },
|
||||
{ provide: Router, useValue: mockRouter },
|
||||
{ provide: I18nService, useValue: mockI18nService },
|
||||
{ provide: PlatformUtilsService, useValue: mockPlatformUtilsService },
|
||||
],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(UpgradeNavButtonComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it("should create", () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
|
||||
describe("upgrade()", () => {
|
||||
describe("when self-hosted", () => {
|
||||
beforeEach(() => {
|
||||
mockPlatformUtilsService.isSelfHost.mockReturnValue(true);
|
||||
});
|
||||
|
||||
it("should navigate to subscription page", async () => {
|
||||
await component.upgrade();
|
||||
|
||||
expect(mockRouter.navigate).toHaveBeenCalledWith(["/settings/subscription/premium"]);
|
||||
expect(mockDialogService.open).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when not self-hosted", () => {
|
||||
beforeEach(() => {
|
||||
mockPlatformUtilsService.isSelfHost.mockReturnValue(false);
|
||||
});
|
||||
|
||||
it("should return early if no active account exists", async () => {
|
||||
activeAccount$.next(null);
|
||||
|
||||
await component.upgrade();
|
||||
|
||||
expect(mockDialogService.open).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should open upgrade dialog with correct configuration", async () => {
|
||||
const mockDialogRef = mock<DialogRef<UnifiedUpgradeDialogResult>>();
|
||||
mockDialogRef.closed = of({ status: UnifiedUpgradeDialogStatus.Closed });
|
||||
mockDialogService.open.mockReturnValue(mockDialogRef);
|
||||
|
||||
await component.upgrade();
|
||||
|
||||
expect(mockDialogService.open).toHaveBeenCalledWith(
|
||||
expect.anything(),
|
||||
expect.objectContaining({
|
||||
data: {
|
||||
account: mockAccount,
|
||||
planSelectionStepTitleOverride: "upgradeYourPlan",
|
||||
hideContinueWithoutUpgradingButton: true,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("should refresh token and sync after upgrading to premium", async () => {
|
||||
const mockDialogRef = mock<DialogRef<UnifiedUpgradeDialogResult>>();
|
||||
mockDialogRef.closed = of({ status: UnifiedUpgradeDialogStatus.UpgradedToPremium });
|
||||
mockDialogService.open.mockReturnValue(mockDialogRef);
|
||||
|
||||
await component.upgrade();
|
||||
|
||||
expect(mockApiService.refreshIdentityToken).toHaveBeenCalled();
|
||||
expect(mockSyncService.fullSync).toHaveBeenCalledWith(true);
|
||||
});
|
||||
|
||||
it("should navigate to organization vault after upgrading to families", async () => {
|
||||
const organizationId = "org-123";
|
||||
const mockDialogRef = mock<DialogRef<UnifiedUpgradeDialogResult>>();
|
||||
mockDialogRef.closed = of({
|
||||
status: UnifiedUpgradeDialogStatus.UpgradedToFamilies,
|
||||
organizationId,
|
||||
});
|
||||
mockDialogService.open.mockReturnValue(mockDialogRef);
|
||||
|
||||
await component.upgrade();
|
||||
|
||||
expect(mockRouter.navigate).toHaveBeenCalledWith([
|
||||
`/organizations/${organizationId}/vault`,
|
||||
]);
|
||||
});
|
||||
|
||||
it("should do nothing when dialog closes without upgrade", async () => {
|
||||
const mockDialogRef = mock<DialogRef<UnifiedUpgradeDialogResult>>();
|
||||
mockDialogRef.closed = of({ status: UnifiedUpgradeDialogStatus.Closed });
|
||||
mockDialogService.open.mockReturnValue(mockDialogRef);
|
||||
|
||||
await component.upgrade();
|
||||
|
||||
expect(mockApiService.refreshIdentityToken).not.toHaveBeenCalled();
|
||||
expect(mockSyncService.fullSync).not.toHaveBeenCalled();
|
||||
expect(mockRouter.navigate).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,11 +1,18 @@
|
||||
import { Component, inject } from "@angular/core";
|
||||
import { Router } from "@angular/router";
|
||||
import { firstValueFrom, lastValueFrom } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { DialogService } from "@bitwarden/components";
|
||||
import { I18nPipe } from "@bitwarden/ui-common";
|
||||
|
||||
import { UnifiedUpgradeDialogComponent } from "../../unified-upgrade-dialog/unified-upgrade-dialog.component";
|
||||
import {
|
||||
UnifiedUpgradeDialogComponent,
|
||||
UnifiedUpgradeDialogStatus,
|
||||
} from "../../unified-upgrade-dialog/unified-upgrade-dialog.component";
|
||||
|
||||
@Component({
|
||||
selector: "app-upgrade-nav-button",
|
||||
@@ -16,8 +23,25 @@ import { UnifiedUpgradeDialogComponent } from "../../unified-upgrade-dialog/unif
|
||||
export class UpgradeNavButtonComponent {
|
||||
private dialogService = inject(DialogService);
|
||||
private accountService = inject(AccountService);
|
||||
private syncService = inject(SyncService);
|
||||
private apiService = inject(ApiService);
|
||||
private router = inject(Router);
|
||||
private platformUtilsService = inject(PlatformUtilsService);
|
||||
|
||||
openUpgradeDialog = async () => {
|
||||
upgrade = async () => {
|
||||
if (this.platformUtilsService.isSelfHost()) {
|
||||
await this.navigateToSelfHostSubscriptionPage();
|
||||
} else {
|
||||
await this.openUpgradeDialog();
|
||||
}
|
||||
};
|
||||
|
||||
private async navigateToSelfHostSubscriptionPage(): Promise<void> {
|
||||
const subscriptionUrl = "/settings/subscription/premium";
|
||||
await this.router.navigate([subscriptionUrl]);
|
||||
}
|
||||
|
||||
private async openUpgradeDialog() {
|
||||
const account = await firstValueFrom(this.accountService.activeAccount$);
|
||||
if (!account) {
|
||||
return;
|
||||
@@ -31,6 +55,14 @@ export class UpgradeNavButtonComponent {
|
||||
},
|
||||
});
|
||||
|
||||
await lastValueFrom(dialogRef.closed);
|
||||
};
|
||||
const result = await lastValueFrom(dialogRef.closed);
|
||||
|
||||
if (result?.status === UnifiedUpgradeDialogStatus.UpgradedToPremium) {
|
||||
await this.apiService.refreshIdentityToken();
|
||||
await this.syncService.fullSync(true);
|
||||
} else if (result?.status === UnifiedUpgradeDialogStatus.UpgradedToFamilies) {
|
||||
const redirectUrl = `/organizations/${result.organizationId}/vault`;
|
||||
await this.router.navigate([redirectUrl]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { Meta, moduleMetadata, StoryObj } from "@storybook/angular";
|
||||
import { of } from "rxjs";
|
||||
|
||||
import { ApiService } from "@bitwarden/common/abstractions/api.service";
|
||||
import { AccountService } from "@bitwarden/common/auth/abstractions/account.service";
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
import { SyncService } from "@bitwarden/common/vault/abstractions/sync/sync.service.abstraction";
|
||||
import { DialogService, I18nMockService } from "@bitwarden/components";
|
||||
import { UpgradeNavButtonComponent } from "@bitwarden/web-vault/app/billing/individual/upgrade/upgrade-nav-button/upgrade-nav-button/upgrade-nav-button.component";
|
||||
|
||||
@@ -40,6 +43,24 @@ export default {
|
||||
}),
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: ApiService,
|
||||
useValue: {
|
||||
refreshIdentityToken: () => {},
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: SyncService,
|
||||
useValue: {
|
||||
fullSync: () => {},
|
||||
},
|
||||
},
|
||||
{
|
||||
provide: PlatformUtilsService,
|
||||
useValue: {
|
||||
isSelfHost: () => false,
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
|
||||
@@ -7,6 +7,8 @@ import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/pl
|
||||
import { EnvironmentSelectorComponent } from "../components/environment-selector/environment-selector.component";
|
||||
import { SharedModule } from "../shared";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "app-frontend-layout",
|
||||
templateUrl: "frontend-layout.component.html",
|
||||
|
||||
@@ -14,6 +14,8 @@ import { MessagingService } from "@bitwarden/common/platform/abstractions/messag
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { UserId } from "@bitwarden/common/types/guid";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "app-header",
|
||||
templateUrl: "./web-header.component.html",
|
||||
@@ -23,11 +25,15 @@ export class WebHeaderComponent {
|
||||
/**
|
||||
* Custom title that overrides the route data `titleId`
|
||||
*/
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input() title: string;
|
||||
|
||||
/**
|
||||
* Icon to show before the title
|
||||
*/
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input() icon: string;
|
||||
|
||||
protected routeData$: Observable<{ titleId: string }>;
|
||||
|
||||
@@ -46,6 +46,8 @@ class MockStateService {
|
||||
accounts$ = new BehaviorSubject({ "1": { profile: { name: "Foo" } } }).asObservable();
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "product-switcher",
|
||||
template: `<button type="button" bitIconButton="bwi-filter" label="Switch products"></button>`,
|
||||
@@ -53,6 +55,8 @@ class MockStateService {
|
||||
})
|
||||
class MockProductSwitcher {}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "dynamic-avatar",
|
||||
template: `<bit-avatar [text]="name$ | async"></bit-avatar>`,
|
||||
@@ -68,6 +72,8 @@ class MockDynamicAvatar implements Partial<DynamicAvatarComponent> {
|
||||
),
|
||||
);
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input()
|
||||
text?: string;
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ import { DialogService, NavigationModule } from "@bitwarden/components";
|
||||
import { OrganizationWarningsModule } from "@bitwarden/web-vault/app/billing/organizations/warnings/organization-warnings.module";
|
||||
import { OrganizationWarningsService } from "@bitwarden/web-vault/app/billing/organizations/warnings/services";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "org-switcher",
|
||||
templateUrl: "org-switcher.component.html",
|
||||
@@ -43,20 +45,28 @@ export class OrgSwitcherComponent {
|
||||
* const smFilter = (org: Organization) => org.canAccessSecretsManager
|
||||
* // <org-switcher [filter]="smFilter">
|
||||
*/
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input()
|
||||
filter: (org: Organization) => boolean = () => true;
|
||||
|
||||
/**
|
||||
* Is `true` if the expanded content is visible
|
||||
*/
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input()
|
||||
open = false;
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
|
||||
@Output()
|
||||
openChange = new EventEmitter<boolean>();
|
||||
|
||||
/**
|
||||
* Visibility of the New Organization button
|
||||
*/
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input()
|
||||
hideNewButton = false;
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ import { ProductSwitcherItem, ProductSwitcherService } from "../shared/product-s
|
||||
|
||||
import { NavigationProductSwitcherComponent } from "./navigation-switcher.component";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "app-upgrade-nav-button",
|
||||
template: "<div>Upgrade Nav Button</div>",
|
||||
|
||||
@@ -3,6 +3,8 @@ import { map, Observable } from "rxjs";
|
||||
|
||||
import { ProductSwitcherItem, ProductSwitcherService } from "../shared/product-switcher.service";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "navigation-product-switcher",
|
||||
templateUrl: "./navigation-switcher.component.html",
|
||||
|
||||
@@ -37,6 +37,8 @@ class MockOrganizationService implements Partial<OrganizationService> {
|
||||
return MockOrganizationService._orgs.asObservable();
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input()
|
||||
set mockOrgs(orgs: Organization[]) {
|
||||
MockOrganizationService._orgs.next(orgs);
|
||||
@@ -54,6 +56,8 @@ class MockProviderService implements Partial<ProviderService> {
|
||||
return MockProviderService._providers.asObservable();
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input()
|
||||
set mockProviders(providers: Provider[]) {
|
||||
MockProviderService._providers.next(providers);
|
||||
@@ -93,6 +97,8 @@ class MockConfigService implements Partial<ConfigService> {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "story-layout",
|
||||
template: `<ng-content></ng-content>`,
|
||||
@@ -100,6 +106,8 @@ class MockConfigService implements Partial<ConfigService> {
|
||||
})
|
||||
class StoryLayoutComponent {}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "story-content",
|
||||
template: ``,
|
||||
|
||||
@@ -6,12 +6,16 @@ import { MenuComponent } from "@bitwarden/components";
|
||||
|
||||
import { ProductSwitcherService } from "./shared/product-switcher.service";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "product-switcher-content",
|
||||
templateUrl: "./product-switcher-content.component.html",
|
||||
standalone: false,
|
||||
})
|
||||
export class ProductSwitcherContentComponent {
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@ViewChild("menu")
|
||||
menu: MenuComponent;
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@ import { AfterViewInit, ChangeDetectorRef, Component, Input } from "@angular/cor
|
||||
import { IconButtonType } from "@bitwarden/components/src/icon-button/icon-button.component";
|
||||
|
||||
import { ProductSwitcherService } from "./shared/product-switcher.service";
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "product-switcher",
|
||||
templateUrl: "./product-switcher.component.html",
|
||||
@@ -14,6 +16,8 @@ export class ProductSwitcherComponent implements AfterViewInit {
|
||||
/**
|
||||
* Passed to the product switcher's `bitIconButton`
|
||||
*/
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input()
|
||||
buttonType: IconButtonType = "main";
|
||||
|
||||
|
||||
@@ -37,6 +37,8 @@ class MockOrganizationService implements Partial<OrganizationService> {
|
||||
return MockOrganizationService._orgs.asObservable();
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input()
|
||||
set mockOrgs(orgs: Organization[]) {
|
||||
MockOrganizationService._orgs.next(orgs);
|
||||
@@ -54,6 +56,8 @@ class MockProviderService implements Partial<ProviderService> {
|
||||
return MockProviderService._providers.asObservable();
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input()
|
||||
set mockProviders(providers: Provider[]) {
|
||||
MockProviderService._providers.next(providers);
|
||||
@@ -93,6 +97,8 @@ class MockConfigService implements Partial<ConfigService> {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "story-layout",
|
||||
template: `<ng-content></ng-content>`,
|
||||
@@ -100,6 +106,8 @@ class MockConfigService implements Partial<ConfigService> {
|
||||
})
|
||||
class StoryLayoutComponent {}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "story-content",
|
||||
template: ``,
|
||||
|
||||
@@ -4,6 +4,8 @@ import { Component } from "@angular/core";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
import { NavigationModule } from "@bitwarden/components";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "app-toggle-width",
|
||||
template: `<bit-nav-item
|
||||
|
||||
@@ -16,6 +16,8 @@ import { BillingFreeFamiliesNavItemComponent } from "../billing/shared/billing-f
|
||||
|
||||
import { WebLayoutModule } from "./web-layout.module";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "app-user-layout",
|
||||
templateUrl: "user-layout.component.html",
|
||||
|
||||
@@ -5,6 +5,8 @@ import { LayoutComponent } from "@bitwarden/components";
|
||||
|
||||
import { ProductSwitcherModule } from "./product-switcher/product-switcher.module";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "app-layout",
|
||||
templateUrl: "web-layout.component.html",
|
||||
|
||||
@@ -6,11 +6,15 @@ import { SideNavVariant, NavigationModule } from "@bitwarden/components";
|
||||
import { ProductSwitcherModule } from "./product-switcher/product-switcher.module";
|
||||
import { ToggleWidthComponent } from "./toggle-width.component";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "app-side-nav",
|
||||
templateUrl: "web-side-nav.component.html",
|
||||
imports: [CommonModule, NavigationModule, ProductSwitcherModule, ToggleWidthComponent],
|
||||
})
|
||||
export class WebSideNavComponent {
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input() variant: SideNavVariant = "primary";
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { setA11yTitleAndAriaLabel } from "./set-a11y-title-and-aria-label";
|
||||
selector: "[appA11yTitle]",
|
||||
})
|
||||
export class A11yTitleDirective {
|
||||
title = input.required<string>({ alias: "appA11yTitle" });
|
||||
readonly title = input.required<string>({ alias: "appA11yTitle" });
|
||||
|
||||
constructor(private el: ElementRef) {
|
||||
const originalTitle = this.el.nativeElement.getAttribute("title");
|
||||
|
||||
@@ -46,6 +46,8 @@ export interface AnonLayoutWrapperData {
|
||||
hideBackgroundIllustration?: boolean;
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
templateUrl: "anon-layout-wrapper.component.html",
|
||||
imports: [AnonLayoutComponent, RouterModule],
|
||||
|
||||
@@ -103,6 +103,8 @@ type Story = StoryObj<AnonLayoutWrapperComponent>;
|
||||
|
||||
// Default Example
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-default-primary-outlet-example-component",
|
||||
template: "<p>Primary Outlet Example: <br> your primary component goes here</p>",
|
||||
@@ -110,6 +112,8 @@ type Story = StoryObj<AnonLayoutWrapperComponent>;
|
||||
})
|
||||
export class DefaultPrimaryOutletExampleComponent {}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-default-secondary-outlet-example-component",
|
||||
template: "<p>Secondary Outlet Example: <br> your secondary component goes here</p>",
|
||||
@@ -117,6 +121,8 @@ export class DefaultPrimaryOutletExampleComponent {}
|
||||
})
|
||||
export class DefaultSecondaryOutletExampleComponent {}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-default-env-selector-outlet-example-component",
|
||||
template: "<p>Env Selector Outlet Example: <br> your env selector component goes here</p>",
|
||||
@@ -192,6 +198,8 @@ const changedData: AnonLayoutWrapperData = {
|
||||
pageIcon: RegistrationCheckEmailIcon,
|
||||
};
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-dynamic-content-example-component",
|
||||
template: `
|
||||
|
||||
@@ -27,6 +27,8 @@ import { TypographyModule } from "../typography";
|
||||
|
||||
export type AnonLayoutMaxWidth = "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "auth-anon-layout",
|
||||
templateUrl: "./anon-layout.component.html",
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "app-root",
|
||||
template: "",
|
||||
|
||||
@@ -39,6 +39,8 @@ const template = `
|
||||
<button class="tw-me-2" type="button" buttonType="muted" bitIconButton="bwi-star" label="Delete" bitFormButton [bitAction]="delete">Delete</button>
|
||||
</form>`;
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "app-promise-example",
|
||||
template,
|
||||
@@ -84,6 +86,8 @@ class PromiseExampleComponent {
|
||||
};
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "app-observable-example",
|
||||
template,
|
||||
|
||||
@@ -20,6 +20,8 @@ const template = /*html*/ `
|
||||
</button>
|
||||
<button type="button" label="Delete" bitIconButton="bwi-trash" buttonType="danger" [bitAction]="action"></button>`;
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
template,
|
||||
selector: "app-promise-example",
|
||||
@@ -37,6 +39,8 @@ class PromiseExampleComponent {
|
||||
};
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
template,
|
||||
selector: "app-action-resolves-quickly",
|
||||
@@ -55,6 +59,8 @@ class ActionResolvesQuicklyComponent {
|
||||
};
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
template,
|
||||
selector: "app-observable-example",
|
||||
@@ -66,6 +72,8 @@ class ObservableExampleComponent {
|
||||
};
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
template,
|
||||
selector: "app-rejected-promise-example",
|
||||
|
||||
@@ -19,6 +19,8 @@ const SizeClasses: Record<SizeTypes, string[]> = {
|
||||
* A variance in color across the avatar component is important as it is used in Account Switching as a
|
||||
* visual indicator to recognize which of a personal or work account a user is logged into.
|
||||
*/
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-avatar",
|
||||
template: `
|
||||
|
||||
@@ -8,6 +8,8 @@ function transformMaxItems(value: number | undefined) {
|
||||
return value == undefined ? undefined : Math.max(1, value);
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-badge-list",
|
||||
templateUrl: "badge-list.component.html",
|
||||
|
||||
@@ -55,6 +55,8 @@ const hoverStyles: Record<BadgeVariant, string[]> = {
|
||||
* > `NOTE:` The `disabled` state only applies to buttons.
|
||||
*
|
||||
*/
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "span[bitBadge], a[bitBadge], button[bitBadge]",
|
||||
providers: [{ provide: FocusableElement, useExisting: BadgeComponent }],
|
||||
|
||||
@@ -23,6 +23,8 @@ const defaultIcon: Record<BannerType, string> = {
|
||||
* - Avoid stacking multiple banners.
|
||||
* - Banners can contain a button or anchor that uses the `bitLink` directive with `linkType="secondary"`.
|
||||
*/
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-banner",
|
||||
templateUrl: "./banner.component.html",
|
||||
@@ -40,6 +42,8 @@ export class BannerComponent implements OnInit {
|
||||
readonly useAlertRole = input(true);
|
||||
readonly showClose = input(true);
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
|
||||
@Output() onClose = new EventEmitter<void>();
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { Component, EventEmitter, Output, TemplateRef, input, viewChild } from "@angular/core";
|
||||
import { QueryParamsHandling } from "@angular/router";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-breadcrumb",
|
||||
templateUrl: "./breadcrumb.component.html",
|
||||
@@ -14,6 +16,8 @@ export class BreadcrumbComponent {
|
||||
|
||||
readonly queryParamsHandling = input<QueryParamsHandling>();
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
|
||||
@Output()
|
||||
click = new EventEmitter();
|
||||
|
||||
|
||||
@@ -15,6 +15,8 @@ import { BreadcrumbComponent } from "./breadcrumb.component";
|
||||
* Bitwarden uses this component to indicate the user's current location in a set of data organized in
|
||||
* containers (Collections, Folders, or Projects).
|
||||
*/
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-breadcrumbs",
|
||||
templateUrl: "./breadcrumbs.component.html",
|
||||
@@ -25,6 +27,8 @@ export class BreadcrumbsComponent {
|
||||
|
||||
private breadcrumbs: BreadcrumbComponent[] = [];
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@ContentChildren(BreadcrumbComponent)
|
||||
protected set breadcrumbList(value: QueryList<BreadcrumbComponent>) {
|
||||
this.breadcrumbs = value.toArray();
|
||||
|
||||
@@ -18,6 +18,8 @@ interface Breadcrumb {
|
||||
route: string;
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
template: "",
|
||||
})
|
||||
|
||||
@@ -56,6 +56,8 @@ describe("Button", () => {
|
||||
});
|
||||
});
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "test-app",
|
||||
template: `
|
||||
|
||||
@@ -57,6 +57,8 @@ const buttonStyles: Record<ButtonType, string[]> = {
|
||||
unstyled: [],
|
||||
};
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "button[bitButton], a[bitButton]",
|
||||
templateUrl: "button.component.html",
|
||||
@@ -97,7 +99,7 @@ export class ButtonComponent implements ButtonLikeAbstraction {
|
||||
.concat(buttonSizeStyles[this.size() || "default"]);
|
||||
}
|
||||
|
||||
protected disabledAttr = computed(() => {
|
||||
protected readonly disabledAttr = computed(() => {
|
||||
const disabled = this.disabled() != null && this.disabled() !== false;
|
||||
return disabled || this.loading();
|
||||
});
|
||||
@@ -110,7 +112,7 @@ export class ButtonComponent implements ButtonLikeAbstraction {
|
||||
* We can't use `disabledAttr` for this, because it returns `true` when `loading` is `true`.
|
||||
* We only want to show disabled styles during loading if `showLoadingStyles` is `true`.
|
||||
*/
|
||||
protected showDisabledStyles = computed(() => {
|
||||
protected readonly showDisabledStyles = computed(() => {
|
||||
return this.showLoadingStyle() || (this.disabledAttr() && this.loading() === false);
|
||||
});
|
||||
|
||||
@@ -134,11 +136,11 @@ export class ButtonComponent implements ButtonLikeAbstraction {
|
||||
* This pattern of converting a signal to an observable and back to a signal is not
|
||||
* recommended. TODO -- find better way to use debounce with signals (CL-596)
|
||||
*/
|
||||
protected showLoadingStyle = toSignal(
|
||||
protected readonly showLoadingStyle = toSignal(
|
||||
toObservable(this.loading).pipe(debounce((isLoading) => interval(isLoading ? 75 : 0))),
|
||||
);
|
||||
|
||||
disabled = model<boolean>(false);
|
||||
readonly disabled = model<boolean>(false);
|
||||
private el = inject(ElementRef<HTMLButtonElement>);
|
||||
|
||||
constructor() {
|
||||
|
||||
@@ -28,6 +28,8 @@ let nextId = 0;
|
||||
* sparingly, as they command a large amount of visual attention. Avoid using more than 1 callout in
|
||||
* the same location.
|
||||
*/
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-callout",
|
||||
templateUrl: "callout.component.html",
|
||||
|
||||
@@ -3,6 +3,8 @@ import { NgControl, Validators } from "@angular/forms";
|
||||
|
||||
import { BitFormControlAbstraction } from "../form-control";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "input[type=checkbox][bitCheckbox]",
|
||||
template: "",
|
||||
|
||||
@@ -28,6 +28,8 @@ const template = /*html*/ `
|
||||
</form>
|
||||
`;
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "app-example",
|
||||
template,
|
||||
@@ -38,10 +40,14 @@ class ExampleComponent {
|
||||
checkbox: [false, Validators.requiredTrue],
|
||||
});
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input() set checked(value: boolean) {
|
||||
this.formObj.patchValue({ checkbox: value });
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input() set disabled(disable: boolean) {
|
||||
if (disable) {
|
||||
this.formObj.disable();
|
||||
|
||||
@@ -35,6 +35,8 @@ export type ChipSelectOption<T> = Option<T> & {
|
||||
/**
|
||||
* `<bit-chip-select>` is a select element that is commonly used to filter items in lists or tables.
|
||||
*/
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-chip-select",
|
||||
templateUrl: "chip-select.component.html",
|
||||
@@ -49,6 +51,8 @@ export type ChipSelectOption<T> = Option<T> & {
|
||||
})
|
||||
export class ChipSelectComponent<T = unknown> implements ControlValueAccessor, AfterViewInit {
|
||||
readonly menu = viewChild(MenuComponent);
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@ViewChildren(MenuItemDirective) menuItems?: QueryList<MenuItemDirective>;
|
||||
readonly chipSelectButton = viewChild<ElementRef<HTMLButtonElement>>("chipSelectButton");
|
||||
|
||||
@@ -63,6 +67,8 @@ export class ChipSelectComponent<T = unknown> implements ControlValueAccessor, A
|
||||
// TODO: Skipped for signal migration because:
|
||||
// Accessor inputs cannot be migrated as they are too complex.
|
||||
/** The select options to render */
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input({ required: true })
|
||||
get options(): ChipSelectOption<T>[] {
|
||||
return this._options;
|
||||
@@ -75,6 +81,8 @@ export class ChipSelectComponent<T = unknown> implements ControlValueAccessor, A
|
||||
/** Disables the entire chip */
|
||||
// TODO: Skipped for signal migration because:
|
||||
// Your application code writes to the input. This prevents migration.
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input({ transform: booleanAttribute }) disabled = false;
|
||||
|
||||
/** Chip will stretch to full width of its container */
|
||||
@@ -83,7 +91,7 @@ export class ChipSelectComponent<T = unknown> implements ControlValueAccessor, A
|
||||
/**
|
||||
* We have `:focus-within` and `:focus-visible` but no `:focus-visible-within`
|
||||
*/
|
||||
protected focusVisibleWithin = signal(false);
|
||||
protected readonly focusVisibleWithin = signal(false);
|
||||
@HostListener("focusin", ["$event.target"])
|
||||
onFocusIn(target: HTMLElement) {
|
||||
this.focusVisibleWithin.set(target.matches("[data-fvw-target]:focus-visible"));
|
||||
|
||||
@@ -9,6 +9,8 @@ type CharacterType = "letter" | "emoji" | "special" | "number";
|
||||
* the logic for displaying letters as `text-main`, numbers as `primary`, and special symbols as
|
||||
* `danger`.
|
||||
*/
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-color-password",
|
||||
template: `@for (character of passwordCharArray(); track $index; let i = $index) {
|
||||
@@ -21,11 +23,11 @@ type CharacterType = "letter" | "emoji" | "special" | "number";
|
||||
}`,
|
||||
})
|
||||
export class ColorPasswordComponent {
|
||||
password = input<string>("");
|
||||
showCount = input<boolean>(false);
|
||||
readonly password = input<string>("");
|
||||
readonly showCount = input<boolean>(false);
|
||||
|
||||
// Convert to an array to handle cases that strings have special characters, i.e.: emoji.
|
||||
passwordCharArray = computed(() => {
|
||||
readonly passwordCharArray = computed(() => {
|
||||
return Array.from(this.password() ?? "");
|
||||
});
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ import { Component } from "@angular/core";
|
||||
/**
|
||||
* bit-container is a minimally styled component that limits the max width of its content to the tailwind theme variable '4xl'. '4xl' is equal to the value of 56rem
|
||||
*/
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-container",
|
||||
templateUrl: "container.component.html",
|
||||
|
||||
@@ -9,6 +9,8 @@ import { ToastService, CopyClickListener, COPY_CLICK_LISTENER } from "../";
|
||||
|
||||
import { CopyClickDirective } from "./copy-click.directive";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
template: `
|
||||
<button type="button" appCopyClick="no toast shown" #noToast></button>
|
||||
@@ -25,9 +27,17 @@ import { CopyClickDirective } from "./copy-click.directive";
|
||||
imports: [CopyClickDirective],
|
||||
})
|
||||
class TestCopyClickComponent {
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@ViewChild("noToast") noToastButton!: ElementRef<HTMLButtonElement>;
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@ViewChild("infoToast") infoToastButton!: ElementRef<HTMLButtonElement>;
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@ViewChild("successToast") successToastButton!: ElementRef<HTMLButtonElement>;
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@ViewChild("toastWithLabel") toastWithLabelButton!: ElementRef<HTMLButtonElement>;
|
||||
}
|
||||
|
||||
|
||||
@@ -26,11 +26,11 @@ export const COPY_CLICK_LISTENER = new InjectionToken<CopyClickListener>("CopyCl
|
||||
selector: "[appCopyClick]",
|
||||
})
|
||||
export class CopyClickDirective {
|
||||
private _showToast = computed(() => {
|
||||
private readonly _showToast = computed(() => {
|
||||
return this.showToast() !== undefined;
|
||||
});
|
||||
|
||||
private toastVariant = computed(() => {
|
||||
private readonly toastVariant = computed(() => {
|
||||
const showToast = this.showToast();
|
||||
// When the `showToast` is set without a value, an empty string will be passed
|
||||
if (showToast === "" || showToast === undefined) {
|
||||
@@ -68,7 +68,7 @@ export class CopyClickDirective {
|
||||
* <app-component [appCopyClick]="value to copy" showToast="info"/></app-component>
|
||||
* ```
|
||||
*/
|
||||
showToast = input<ToastVariant | "">();
|
||||
readonly showToast = input<ToastVariant | "">();
|
||||
|
||||
@HostListener("click") onClick() {
|
||||
const valueToCopy = this.valueToCopy();
|
||||
|
||||
@@ -21,6 +21,8 @@ interface Animal {
|
||||
animal: string;
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
template: `
|
||||
<bit-layout>
|
||||
@@ -62,6 +64,8 @@ class StoryDialogComponent {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
template: `
|
||||
<bit-dialog title="Dialog Title" dialogSize="large">
|
||||
@@ -91,6 +95,8 @@ class StoryDialogContentComponent {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
template: `
|
||||
<bit-dialog
|
||||
|
||||
@@ -26,6 +26,8 @@ import { DialogRef } from "../dialog.service";
|
||||
import { DialogCloseDirective } from "../directives/dialog-close.directive";
|
||||
import { DialogTitleContainerDirective } from "../directives/dialog-title-container.directive";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-dialog",
|
||||
templateUrl: "./dialog.component.html",
|
||||
@@ -47,8 +49,8 @@ import { DialogTitleContainerDirective } from "../directives/dialog-title-contai
|
||||
})
|
||||
export class DialogComponent {
|
||||
private readonly destroyRef = inject(DestroyRef);
|
||||
private scrollableBody = viewChild.required(CdkScrollable);
|
||||
private scrollBottom = viewChild.required<ElementRef<HTMLDivElement>>("scrollBottom");
|
||||
private readonly scrollableBody = viewChild.required(CdkScrollable);
|
||||
private readonly scrollBottom = viewChild.required<ElementRef<HTMLDivElement>>("scrollBottom");
|
||||
|
||||
protected dialogRef = inject(DialogRef, { optional: true });
|
||||
protected bodyHasScrolledFrom = hasScrolledFrom(this.scrollableBody);
|
||||
|
||||
@@ -26,6 +26,8 @@ const DEFAULT_COLOR: Record<SimpleDialogType, string> = {
|
||||
danger: "tw-text-danger",
|
||||
};
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
templateUrl: "./simple-configurable-dialog.component.html",
|
||||
imports: [
|
||||
|
||||
@@ -10,6 +10,8 @@ import { CalloutModule } from "../../../callout";
|
||||
import { I18nMockService } from "../../../utils/i18n-mock.service";
|
||||
import { DialogModule } from "../../dialog.module";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
template: `
|
||||
@for (group of dialogs; track group) {
|
||||
|
||||
@@ -9,6 +9,8 @@ import { DialogTitleContainerDirective } from "../directives/dialog-title-contai
|
||||
})
|
||||
export class IconDirective {}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-simple-dialog",
|
||||
templateUrl: "./simple-dialog.component.html",
|
||||
@@ -16,12 +18,14 @@ export class IconDirective {}
|
||||
imports: [DialogTitleContainerDirective, TypographyDirective],
|
||||
})
|
||||
export class SimpleDialogComponent {
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@ContentChild(IconDirective) icon!: IconDirective;
|
||||
|
||||
/**
|
||||
* Optional flag to hide the dialog's center icon. Defaults to false.
|
||||
*/
|
||||
hideIcon = input(false, { transform: booleanAttribute });
|
||||
readonly hideIcon = input(false, { transform: booleanAttribute });
|
||||
|
||||
get hasIcon() {
|
||||
return this.icon != null;
|
||||
|
||||
@@ -15,6 +15,8 @@ interface Animal {
|
||||
animal: string;
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
template: `
|
||||
<button type="button" bitButton (click)="openSimpleDialog()">Open Simple Dialog</button>
|
||||
@@ -57,6 +59,8 @@ class StoryDialogComponent {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
template: `
|
||||
<bit-simple-dialog>
|
||||
@@ -87,6 +91,8 @@ class SimpleDialogContent {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
template: `
|
||||
<bit-simple-dialog>
|
||||
@@ -116,6 +122,8 @@ class NonDismissableWithPrimaryButtonContent {
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
template: `
|
||||
<bit-simple-dialog>
|
||||
|
||||
@@ -34,12 +34,16 @@ let nextId = 0;
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-disclosure",
|
||||
template: `<ng-content></ng-content>`,
|
||||
})
|
||||
export class DisclosureComponent {
|
||||
/** Emits the visibility of the disclosure content */
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
|
||||
@Output() openChange = new EventEmitter<boolean>();
|
||||
|
||||
private _open?: boolean;
|
||||
@@ -48,6 +52,8 @@ export class DisclosureComponent {
|
||||
*/
|
||||
// TODO: Skipped for signal migration because:
|
||||
// Accessor inputs cannot be migrated as they are too complex.
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input({ transform: booleanAttribute }) set open(isOpen: boolean) {
|
||||
this._open = isOpen;
|
||||
this.openChange.emit(isOpen);
|
||||
|
||||
@@ -24,7 +24,7 @@ export class DrawerHeaderComponent {
|
||||
/**
|
||||
* The title to display
|
||||
*/
|
||||
title = input.required<string>();
|
||||
readonly title = input.required<string>();
|
||||
|
||||
/** We don't want to set the HTML title attribute with `this.title` */
|
||||
@HostBinding("attr.title")
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Directive, signal } from "@angular/core";
|
||||
selector: "[bitDrawerHost]",
|
||||
})
|
||||
export class DrawerHostDirective {
|
||||
private _portal = signal<Portal<unknown> | undefined>(undefined);
|
||||
private readonly _portal = signal<Portal<unknown> | undefined>(undefined);
|
||||
|
||||
/** The portal to display */
|
||||
portal = this._portal.asReadonly();
|
||||
|
||||
@@ -25,7 +25,7 @@ import { DrawerService } from "./drawer.service";
|
||||
})
|
||||
export class DrawerComponent {
|
||||
private drawerHost = inject(DrawerService);
|
||||
private portal = viewChild.required(CdkPortal);
|
||||
private readonly portal = viewChild.required(CdkPortal);
|
||||
|
||||
/**
|
||||
* Whether or not the drawer is open.
|
||||
@@ -33,7 +33,7 @@ export class DrawerComponent {
|
||||
* Note: Does not support implicit boolean transform due to Angular limitation. Must be bound explicitly `[open]="true"` instead of just `open`.
|
||||
* https://github.com/angular/angular/issues/55166#issuecomment-2032150999
|
||||
**/
|
||||
open = model<boolean>(false);
|
||||
readonly open = model<boolean>(false);
|
||||
|
||||
/**
|
||||
* The ARIA role of the drawer.
|
||||
@@ -43,7 +43,7 @@ export class DrawerComponent {
|
||||
* - [navigation](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Roles/navigation_role)
|
||||
* - For drawers that primary contain links to other content.
|
||||
*/
|
||||
role = input<"complementary" | "navigation">("complementary");
|
||||
readonly role = input<"complementary" | "navigation">("complementary");
|
||||
|
||||
constructor() {
|
||||
effect(
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Injectable, signal } from "@angular/core";
|
||||
|
||||
@Injectable({ providedIn: "root" })
|
||||
export class DrawerService {
|
||||
private _portal = signal<Portal<unknown> | undefined>(undefined);
|
||||
private readonly _portal = signal<Portal<unknown> | undefined>(undefined);
|
||||
|
||||
/** The portal to display */
|
||||
portal = this._portal.asReadonly();
|
||||
|
||||
@@ -8,6 +8,8 @@ import { TypographyDirective } from "../typography/typography.directive";
|
||||
|
||||
import { BitFormControlAbstraction } from "./form-control.abstraction";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-form-control",
|
||||
templateUrl: "form-control.component.html",
|
||||
|
||||
@@ -6,6 +6,8 @@ import { FormControlComponent } from "./form-control.component";
|
||||
// Increments for each instance of this component
|
||||
let nextId = 0;
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-label",
|
||||
templateUrl: "label.component.html",
|
||||
|
||||
@@ -3,6 +3,8 @@ import { AbstractControl, UntypedFormGroup } from "@angular/forms";
|
||||
|
||||
import { I18nPipe } from "@bitwarden/ui-common";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-error-summary",
|
||||
template: ` @if (errorCount > 0) {
|
||||
|
||||
@@ -5,6 +5,8 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
||||
// Increments for each instance of this component
|
||||
let nextId = 0;
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-error",
|
||||
template: `<i class="bwi bwi-error"></i> {{ displayError }}`,
|
||||
|
||||
@@ -22,6 +22,8 @@ import { inputBorderClasses } from "../input/input.directive";
|
||||
import { BitErrorComponent } from "./error.component";
|
||||
import { BitFormFieldControl } from "./form-field-control";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-form-field",
|
||||
templateUrl: "./form-field.component.html",
|
||||
@@ -42,11 +44,13 @@ export class BitFormFieldComponent implements AfterContentChecked {
|
||||
/** If `true`, remove the bottom border for `readonly` inputs */
|
||||
// TODO: Skipped for signal migration because:
|
||||
// Your application code writes to the input. This prevents migration.
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-signals
|
||||
@Input({ transform: booleanAttribute })
|
||||
disableReadOnlyBorder = false;
|
||||
|
||||
protected prefixHasChildren = signal(false);
|
||||
protected suffixHasChildren = signal(false);
|
||||
protected readonly prefixHasChildren = signal(false);
|
||||
protected readonly suffixHasChildren = signal(false);
|
||||
|
||||
get inputBorderClasses(): string {
|
||||
const shouldFocusBorderAppear = this.defaultContentIsFocused();
|
||||
@@ -87,7 +91,7 @@ export class BitFormFieldComponent implements AfterContentChecked {
|
||||
* This is necessary because the `tw-group/bit-form-field` wraps the input and any prefix/suffix
|
||||
* buttons
|
||||
*/
|
||||
protected defaultContentIsFocused = signal(false);
|
||||
protected readonly defaultContentIsFocused = signal(false);
|
||||
@HostListener("focusin", ["$event.target"])
|
||||
onFocusIn(target: HTMLElement) {
|
||||
this.defaultContentIsFocused.set(target.matches("[data-default-content] *:focus-visible"));
|
||||
|
||||
@@ -27,6 +27,8 @@ export class BitPasswordInputToggleDirective implements AfterContentInit, OnChan
|
||||
* Whether the input is toggled to show the password.
|
||||
*/
|
||||
readonly toggled = model(false);
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-903): Migrate to Signals
|
||||
// eslint-disable-next-line @angular-eslint/prefer-output-emitter-ref
|
||||
@Output() toggledChange = new EventEmitter<boolean>();
|
||||
|
||||
@HostBinding("attr.title") title = this.i18nService.t("toggleVisibility");
|
||||
|
||||
@@ -13,6 +13,8 @@ import { BitFormFieldComponent } from "./form-field.component";
|
||||
import { FormFieldModule } from "./form-field.module";
|
||||
import { BitPasswordInputToggleDirective } from "./password-input-toggle.directive";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "test-form-field",
|
||||
template: `
|
||||
|
||||
@@ -81,6 +81,8 @@ const sizes: Record<IconButtonSize, string[]> = {
|
||||
|
||||
* Similar to the main button components, spacing between multiple icon buttons should be .5rem.
|
||||
*/
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "button[bitIconButton]:not(button[bitButton])",
|
||||
templateUrl: "icon-button.component.html",
|
||||
@@ -143,7 +145,7 @@ export class BitIconButtonComponent implements ButtonLikeAbstraction, FocusableE
|
||||
return [this.icon(), "!tw-m-0"];
|
||||
}
|
||||
|
||||
protected disabledAttr = computed(() => {
|
||||
protected readonly disabledAttr = computed(() => {
|
||||
const disabled = this.disabled() != null && this.disabled() !== false;
|
||||
return disabled || this.loading();
|
||||
});
|
||||
@@ -156,7 +158,7 @@ export class BitIconButtonComponent implements ButtonLikeAbstraction, FocusableE
|
||||
* We can't use `disabledAttr` for this, because it returns `true` when `loading` is `true`.
|
||||
* We only want to show disabled styles during loading if `showLoadingStyles` is `true`.
|
||||
*/
|
||||
protected showDisabledStyles = computed(() => {
|
||||
protected readonly showDisabledStyles = computed(() => {
|
||||
return this.showLoadingStyle() || (this.disabledAttr() && this.loading() === false);
|
||||
});
|
||||
|
||||
@@ -174,7 +176,7 @@ export class BitIconButtonComponent implements ButtonLikeAbstraction, FocusableE
|
||||
* This pattern of converting a signal to an observable and back to a signal is not
|
||||
* recommended. TODO -- find better way to use debounce with signals (CL-596)
|
||||
*/
|
||||
protected showLoadingStyle = toSignal(
|
||||
protected readonly showLoadingStyle = toSignal(
|
||||
toObservable(this.loading).pipe(debounce((isLoading) => interval(isLoading ? 75 : 0))),
|
||||
);
|
||||
|
||||
|
||||
@@ -56,6 +56,8 @@ const shapeStyles: Record<IconTileShape, Record<IconTileSize, string[]>> = {
|
||||
* - Create visual hierarchy in lists or cards
|
||||
* - Show app or service icons in a consistent format
|
||||
*/
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "bit-icon-tile",
|
||||
templateUrl: "icon-tile.component.html",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user