Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 91 additions & 34 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,46 +10,110 @@ on:
- 'scripts/firebase-deploy.js'
- '*.json'
- '.github/deploy'
- '.github/workflows/deploy.yml'
workflow_dispatch:
inputs:
dry_run:
description: 'Validar o deploy sem publicar (--dry-run)'
type: boolean
default: false

jobs:
deploy:
name: Deploy to Firebase
runs-on: ubuntu-latest
if: |
github.event.head_commit.message != 'Initial commit' &&
!contains(github.event.head_commit.message, '[skip ci]')
github.event_name == 'workflow_dispatch' ||
(github.event.head_commit.message != 'Initial commit' &&
!contains(github.event.head_commit.message, '[skip ci]'))

env:
# `secrets` nao pode ser usado direto em `if:`, entao vira env do job
HAS_SA: ${{ secrets.FIREBASE_SERVICE_ACCOUNT != '' }}
FIREBASE_PROJECT_ID: ${{ secrets.FIREBASE_PROJECT_ID }}

steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '18.x'

- name: Cache dependencies
uses: actions/cache@v3
uses: actions/setup-node@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
node-version: '22.x'
cache: 'npm'

- name: Install root dependencies
run: npm i --only=production
run: npm i --omit=dev

- name: Install functions dependencies
run: cd functions && npm i --only=production --no-optional && cd ..
run: npm i --omit=dev --no-optional --prefix functions
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

- name: Run deploy
- name: Write functions/.env
env:
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
FIREBASE_PROJECT_ID: ${{ secrets.FIREBASE_PROJECT_ID }}
SERVER_OPERATOR_TOKEN: ${{ secrets.SERVER_OPERATOR_TOKEN }}
run: npm run deploy
run: npm run write-env

- name: Authenticate with service account
if: env.HAS_SA == 'true'
uses: google-github-actions/auth@v2
with:
credentials_json: ${{ secrets.FIREBASE_SERVICE_ACCOUNT }}

- name: Setup gcloud
if: env.HAS_SA == 'true'
uses: google-github-actions/setup-gcloud@v2

- name: Record deployed state (before)
id: before
if: env.HAS_SA == 'true'
run: |
set -euo pipefail
BEFORE=$(gcloud functions describe app --region us-central1 \
--project "$FIREBASE_PROJECT_ID" --format='value(updateTime)')
echo "updateTime=$BEFORE" >> "$GITHUB_OUTPUT"
echo "updateTime antes do deploy: $BEFORE"

- name: Deploy functions
env:
FIREBASE_TOKEN: ${{ secrets.FIREBASE_TOKEN }}
DRY_RUN: ${{ inputs.dry_run }}
run: |
set -euo pipefail
if [ -z "${FIREBASE_PROJECT_ID:-}" ]; then
echo "::error::secret FIREBASE_PROJECT_ID nao configurado"
exit 1
fi
ARGS=(--only functions --project "$FIREBASE_PROJECT_ID" --non-interactive)
if [ "${DRY_RUN:-false}" = "true" ]; then
ARGS+=(--dry-run)
fi
if [ "${HAS_SA}" = "true" ]; then
echo "Autenticando via service account (ADC)"
elif [ -n "${FIREBASE_TOKEN:-}" ]; then
echo "::warning::Usando FIREBASE_TOKEN (firebase login:ci). O Google descontinuou esse fluxo - migrar para service account, ver issue #177"
ARGS+=(--token "$FIREBASE_TOKEN")
else
echo "::error::Nenhuma credencial disponivel. Configure o secret FIREBASE_SERVICE_ACCOUNT"
exit 1
fi
npx --yes firebase-tools@13 deploy "${ARGS[@]}"

- name: Verify functions were really published
if: env.HAS_SA == 'true' && inputs.dry_run != true
run: |
set -euo pipefail
AFTER=$(gcloud functions describe app --region us-central1 \
--project "$FIREBASE_PROJECT_ID" --format='value(updateTime)')
BEFORE='${{ steps.before.outputs.updateTime }}'
echo "updateTime antes: $BEFORE"
echo "updateTime depois: $AFTER"
if [ "$AFTER" = "$BEFORE" ]; then
echo "::error::O deploy terminou sem erro, mas o updateTime nao avancou: nada foi publicado (ver issue #177)"
exit 1
fi
echo "Deploy confirmado: as functions foram republicadas."

update-app-json:
name: Update application and publish
Expand All @@ -58,7 +122,7 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4

- name: Write README with base URI
env:
Expand All @@ -80,7 +144,8 @@ jobs:
git config --local user.email 'action@github.com'
git config --local user.name 'GitHub Action'
git add ./assets/
(git diff-index --quiet HEAD && echo "::set-output name=diff::0") || echo "::set-output name=diff::1"
(git diff-index --quiet HEAD && echo "diff=0" >> "$GITHUB_OUTPUT") \
|| echo "diff=1" >> "$GITHUB_OUTPUT"
id: git_diff

- name: Commit local file changes
Expand All @@ -100,28 +165,20 @@ jobs:
APP_CHANGED: ${{ steps.git_diff.outputs.diff }}
run: |
CAN_PUBLISH=$(node -p "!(/-/.test(require('./package.json').version)) && process.env.APP_CHANGED")
echo "::set-output name=publish::$CAN_PUBLISH"
echo "publish=$CAN_PUBLISH" >> "$GITHUB_OUTPUT"
id: pkg_version

- name: Setup Node
if: steps.pkg_version.outputs.publish == 1
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: '18.x'
node-version: '22.x'
registry-url: 'https://registry.npmjs.org/'

- name: Cache dependencies
if: steps.pkg_version.outputs.publish == 1
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
cache: 'npm'

- name: Install dependencies
if: steps.pkg_version.outputs.publish == 1
run: npm ci --only=production
run: npm ci --omit=dev

- name: Run publish script
if: steps.pkg_version.outputs.publish == 1
Expand Down
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
18
22
3 changes: 0 additions & 3 deletions firebase.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
{
"functions": {
"predeploy": [
"npm --prefix \"$RESOURCE_DIR\" run"
],
"source": "functions"
}
}
2 changes: 1 addition & 1 deletion functions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"logs": "firebase functions:log"
},
"engines": {
"node": "18"
"node": "22"
},
"dependencies": {
"@ecomplus/application-sdk": "^22.0.0-firestore.1.15.7",
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"main": "functions/index.js",
"scripts": {
"serve": "echo 'Firebase runs with legacy Node.js 8; Use `npm run deploy` instead.'",
"deploy": "NODE_ENV=production node ./scripts/firebase-deploy.js",
"write-env": "NODE_ENV=production node ./scripts/firebase-deploy.js",
"deploy": "npm run write-env && npx --yes firebase-tools@13 deploy --only functions --non-interactive",
"release": "standard-version",
"release:starter": "standard-version --prerelease starter",
"publish:market": "node ./scripts/market-publication.js"
Expand Down
72 changes: 33 additions & 39 deletions scripts/firebase-deploy.js
Original file line number Diff line number Diff line change
@@ -1,51 +1,45 @@
/**
* Gera o arquivo `functions/.env`, lido em runtime por `functions/__env.js`.
*
* Este script NÃO faz mais o deploy. Antes ele chamava a API programática do
* `firebase-tools` (`client.functions.config.set()` + `client.deploy()`), que
* encerrava o processo com exit 0 sem publicar nada — deixando o workflow verde
* enquanto a produção seguia parada. Ver issue #177.
*
* O deploy agora é feito pelo CLI, que falha alto quando algo dá errado:
* firebase deploy --only functions --project <id> --non-interactive
*/

require('dotenv').config()
const path = require('path')
const fs = require('fs')

const { FIREBASE_TOKEN, SERVER_OPERATOR_TOKEN } = process.env

require('./scripts-minification')

const { name, version } = require('../package.json')
const { project, baseUri } = require('./_constants')
const client = require('firebase-tools')

const config = [
`pkg.version=${version}`,
`pkg.name=${name}`,
`server.operator_token=${SERVER_OPERATOR_TOKEN}`
]
if (baseUri) {
config.push(`server.base_uri=${baseUri}`)

const { SERVER_OPERATOR_TOKEN } = process.env

if (!SERVER_OPERATOR_TOKEN) {
console.error('\x1b[31m%s\x1b[0m', 'SERVER_OPERATOR_TOKEN não definido')
console.error(
'As functions rejeitam todo webhook sem esse valor (functions/index.js, x-operator-token).'
)
process.exit(1)
}

fs.writeFileSync(path.resolve(__dirname, '../functions/.env'), `
NAME=${name}
const envFile = path.resolve(__dirname, '../functions/.env')

fs.writeFileSync(envFile, `NAME=${name}
VERSION=${version}
SERVER_OPERATOR_TOKEN=${SERVER_OPERATOR_TOKEN}
SERVER_BASE_URI=${baseUri}`)

client.functions.config.set(config, { project })
.then(() => client.deploy({
project,
only: 'functions',
token: FIREBASE_TOKEN,
force: true
}))

.then(() => {
console.log(
'\x1b[32m%s\x1b[0m',
`\nDeployed with success to Firebase project '${project}'`
)
console.log(
'\x1b[35m%s\x1b[0m',
`\nBase URI: ${baseUri}`
)
console.log()
})

.catch(err => {
console.error(err)
process.exit(1)
})
SERVER_BASE_URI=${baseUri}
`)

console.log('\x1b[32m%s\x1b[0m', `\nfunctions/.env escrito para o projeto '${project}'`)
console.log(` NAME=${name}`)
console.log(` VERSION=${version}`)
console.log(` SERVER_BASE_URI=${baseUri}`)
console.log(' SERVER_OPERATOR_TOKEN=<definido>')
console.log()