name: Build & Deploy to SharePoint Online # Скопировано из tnsu-approval-route (.gitea/workflows/deploy_frontend.yml). # Отличия — только в путях и идентификаторах: там SPFx-проект лежит в подпапке # frontend/, здесь он и есть корень репозитория, поэтому working-directory и # префиксы frontend/ убраны. # # Запуск только вручную (workflow_dispatch): деплой идёт сразу в каталог # приложений тенанта, то есть на прод для всех сайтов. on: workflow_dispatch: jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Set up Node.js 22 uses: actions/setup-node@v3 with: node-version: '22' cache: 'npm' cache-dependency-path: package-lock.json - name: Install dependencies run: | npm config set fetch-retries 5 npm config set fetch-retry-mintimeout 10000 npm config set fetch-retry-maxtimeout 120000 for i in 1 2 3; do npm install --legacy-peer-deps && break echo "Attempt $i failed, retrying in 20s..." sleep 20 done # npm run build = heft test --production (сборка + lint + Jest) и следом # heft package-solution --production, который и создаёт .sppkg. - name: Build & package SPFx solution run: npm run build - name: Upload .sppkg artifact uses: actions/upload-artifact@v3 with: name: request-portal-sppkg path: sharepoint/solution/request-portal.sppkg retention-days: 7 - name: Install CLI for Microsoft 365 run: | for i in 1 2 3; do npm install -g @pnp/cli-microsoft365@9 && break echo "Attempt $i failed, retrying in 20s..." sleep 20 done - name: Login to Microsoft 365 (certificate) run: | m365 login \ --authType certificate \ --appId "${{ secrets.SPO_CLIENT_ID }}" \ --certificateBase64Encoded "${{ secrets.SPO_CERT_BASE64 }}" \ --thumbprint "${{ secrets.SPO_CERT_THUMBPRINT }}" \ --tenant "${{ secrets.SPO_TENANT_ID }}" # SOLUTION_ID — solution.id из config/package-solution.json; при его смене # правится и здесь, иначе deploy уйдёт в чужое приложение. - name: Upload & Deploy to App Catalog env: SOLUTION_ID: "8c31266a-712c-4c72-ae04-bca5a6a071c3" CATALOG_SITE: "https://tnsukz.sharepoint.com/sites/appcatalog" SPPKG: "sharepoint/solution/request-portal.sppkg" FILE_NAME: "request-portal.sppkg" run: | # Получаем токен через уже аутентифицированный m365 CLI TOKEN=$(m365 util accesstoken get --resource https://tnsukz.sharepoint.com --output text) echo "Token length: ${#TOKEN}" echo ">>> Uploading to App Catalog" HTTP=$(curl -s -o /tmp/upload.json -w "%{http_code}" -X POST \ "${CATALOG_SITE}/_api/web/GetFolderByServerRelativeUrl('/sites/appcatalog/AppCatalog')/Files/add(overwrite=true,url='${FILE_NAME}')" \ -H "Authorization: Bearer ${TOKEN}" \ -H "X-RequestDigest: 0x0" \ -H "Accept: application/json;odata=nometadata" \ -H "Content-Type: application/octet-stream" \ --data-binary @"${SPPKG}" || echo "000") echo "Upload HTTP: ${HTTP}" cat /tmp/upload.json [ "$HTTP" = "200" ] || [ "$HTTP" = "201" ] || exit 1 echo ">>> Deploying app (id: ${SOLUTION_ID})" HTTP=$(curl -s -o /tmp/deploy.json -w "%{http_code}" -X POST \ "${CATALOG_SITE}/_api/web/tenantappcatalog/AvailableApps/GetById('${SOLUTION_ID}')/deploy" \ -H "Authorization: Bearer ${TOKEN}" \ -H "X-RequestDigest: 0x0" \ -H "Accept: application/json;odata=nometadata" \ -H "Content-Type: application/json" \ -d '{"skipFeatureDeployment":true}' || echo "000") echo "Deploy HTTP: ${HTTP}" cat /tmp/deploy.json [ "$HTTP" = "200" ] || [ "$HTTP" = "204" ] || exit 1 echo ">>> Done"