Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add deploy preview workflow #904

Merged
merged 11 commits into from
Nov 28, 2024
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
22 changes: 22 additions & 0 deletions .github/workflows/deploy-pr-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
name: Deploy pr preview

on:
pull_request:
types:
- opened
- synchronize
- closed
paths:
- "docs/sources/**"

jobs:
deploy-pr-preview:
uses: grafana/writers-toolkit/.github/workflows/deploy-preview.yml@main
with:
sha: ${{ github.event.pull_request.head.sha }}
branch: ${{ github.head_ref }}
event_number: ${{ github.event.number }}
title: ${{ github.event.pull_request.title }}
repo: writers-toolkit
website_directory: content/docs/writers-toolkit
relative_prefix: /docs/writers-toolkit/
195 changes: 195 additions & 0 deletions .github/workflows/deploy-preview.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,195 @@
name: deploy-preview

on:
workflow_call:
inputs:
sha:
required: true
type: string
branch:
required: true
type: string
event_number:
required: true
type: string
title:
required: true
type: string
repo:
required: true
type: string
source_directory:
default: docs/sources
type: string
website_directory:
required: true
type: string
relative_prefix:
required: true
type: string

env:
CLOUD_RUN_REGION: us-south1

permissions:
id-token: write # Needed for authentication.
statuses: write # Needed to send deploy preview link as a commit status.
pull-requests: write # Needed to add/update a comment with the deploy preview link.

concurrency:
group: ${{ github.workflow }}-${{ inputs.repo }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
deploy-preview:
permissions: write-all
runs-on: ubuntu-latest
steps:
- name: Find comment
uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e # v3.1.0
id: fc
with:
issue-number: ${{ inputs.event_number }}
comment-author: "github-actions[bot]"
body-includes: Deploy preview available

- name: Update comment with in-progress deploy preview
if: steps.fc.outputs.comment-id != '' && github.event.action == 'opened' || github.event.action == 'synchronize'
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
with:
comment-id: ${{ steps.fc.outputs.comment-id }}
issue-number: ${{ inputs.event_number }}
edit-mode: append
append-separator: newline
body: |
:building_construction: Updating deploy preview...

- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
if: github.event.action == 'opened' || github.event.action == 'synchronize'

# get the Dockerfile and nginx conf
- name: Sparse checkout
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
if: github.event.action == 'opened' || github.event.action == 'synchronize'
with:
repository: "grafana/writers-toolkit"
ref: "main"
path: deploy-preview-files
sparse-checkout: |
deploy-preview

- name: Build website
if: github.event.action == 'opened' || github.event.action == 'synchronize'
shell: bash
run: |
mkdir -p ${PWD}/dist
docker run -v ${PWD}/dist:/hugo/dist -v "${PWD}/${{ inputs.source_directory }}:/hugo/${{ inputs.website_directory }}" --rm grafana/docs-base:latest /bin/bash -c 'HUGO_SSI=false hugo --environment=docs --destination=dist/ --baseURL= --minify'
printf "%s" "add_header 'Build' '"${{ inputs.sha }}"';" > build.conf

- uses: google-github-actions/auth@6fc4af4b145ae7821d527454aa9bd537d1f2dc5f # v2.1.7
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Couldn't you use https://github.com/grafana/shared-workflows/tree/main/actions/push-to-gar-docker for this and the following steps without requiring a custom service account?

Copy link
Contributor Author

@robbymilo robbymilo Nov 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The service account in login-to-gar (https://github.com/grafana/shared-workflows/blob/main/actions/login-to-gar/action.yaml#L27), which is called from push-to-gar, is hard coded from the output of the construct-service-account step.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to explore this in a follow up. I don't mind that the same service account handles all the aspects of this service.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The service account in the shared-workflow is currently just an implementation detail and IIRC @dsotirakis is investigating if we can completely get rid of it 🙂 That was the main reason for me asking about this here but it's absolutely not required 🙂

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The service account in the shared-workflow is currently just an implementation detail and IIRC @dsotirakis is investigating if we can completely get rid of it 🙂 That was the main reason for me asking about this here but it's absolutely not required 🙂

Good to know! I'm subscribed to all activity on the grafana/shared-workflows repository so if something moves there, we'll know :)

Thanks for clarifying

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy to come back and update if we can get rid of it!

if: github.event.action == 'opened' || github.event.action == 'synchronize'
id: gcloud-auth
with:
token_format: access_token
workload_identity_provider: "projects/304398677251/locations/global/workloadIdentityPools/github/providers/github-provider"
service_account: github-docs-deploy-previews@grafanalabs-workload-identity.iam.gserviceaccount.com
create_credentials_file: false

- name: Login to GAR
if: github.event.action == 'opened' || github.event.action == 'synchronize'
uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0
with:
registry: us-docker.pkg.dev
username: oauth2accesstoken
password: ${{ steps.gcloud-auth.outputs.access_token }}

- name: Extract metadata (tags, labels) for Docker
if: github.event.action == 'opened' || github.event.action == 'synchronize'
id: meta
uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # v5.5.1
with:
images: "us-docker.pkg.dev/grafanalabs-dev/docker-docs-previews-dev/${{ inputs.repo }}"
tags: |-
"${{ inputs.sha }}"
"${{ inputs.event_number }}"

- name: Set up Docker Buildx
if: github.event.action == 'opened' || github.event.action == 'synchronize'
uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1
with:
driver: docker-container

- name: Build the container
if: github.event.action == 'opened' || github.event.action == 'synchronize'
uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0
id: build
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
file: ./deploy-preview-files/deploy-preview/Dockerfile

- uses: google-github-actions/auth@8254fb75a33b976a221574d287e93919e6a36f70 # v2.1.6
id: gcloud-auth-cloud-run
with:
workload_identity_provider: "projects/304398677251/locations/global/workloadIdentityPools/github/providers/github-provider"
service_account: "github-docs-cloud-run-dev@grafanalabs-workload-identity.iam.gserviceaccount.com"

- name: Deploy to Cloud Run
uses: google-github-actions/deploy-cloudrun@1ec29da1351112c7904fb60454a55e3e1021a51c # v2.7.2
if: github.event.action == 'opened' || github.event.action == 'synchronize'
id: deploy
with:
image: us-docker.pkg.dev/grafanalabs-dev/docker-docs-previews-dev/${{ inputs.repo }}:${{ inputs.sha }}
service: deploy-preview-${{ inputs.repo }}-${{ inputs.event_number }}
project_id: grafanalabs-dev
region: ${{ env.CLOUD_RUN_REGION }}
flags: --port=80 --ingress=all --allow-unauthenticated

- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@6189d56e4096ee891640bb02ac264be376592d6a # v2.1.2
if: github.event.action == 'closed'
with:
project_id: grafanalabs-dev

- name: Delete deploy preview
if: github.event.action == 'closed'
run: |
gcloud run services delete deploy-preview-${{ inputs.repo }}-${{ inputs.event_number }} --region=${{ env.CLOUD_RUN_REGION }} --project=grafanalabs-dev --quiet

- name: Send commit status
uses: ouzi-dev/commit-status-updater@26588d166ff273fc4c0664517359948f7cdc9bf1 # v2.0.2
if: github.event.action == 'opened' || github.event.action == 'synchronize'
with:
name: deploy_preview
status: "${{ job.status }}"
url: "${{ steps.deploy.outputs.url }}${{ inputs.relative_prefix }}"
description: "Public deploy preview"

- name: Create comment with available deploy preview
if: github.event.action == 'opened' || github.event.action == 'synchronize' && steps.fc.outputs.comment-id == ''
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
with:
issue-number: ${{ inputs.event_number }}
body: |
:computer: Deploy preview available: ${{ steps.deploy.outputs.url }}${{ inputs.relative_prefix }}

- name: Update comment with deleted deploy preview
if: github.event.action == 'closed'
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
with:
issue-number: ${{ inputs.event_number }}
comment-id: ${{ steps.fc.outputs.comment-id }}
edit-mode: replace
body: |
:computer: Deploy preview deleted.

- name: Update comment with available deploy preview
if: github.event.action == 'opened' || github.event.action == 'synchronize' && steps.fc.outputs.comment-id != ''
uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0
with:
comment-id: ${{ steps.fc.outputs.comment-id }}
issue-number: ${{ inputs.event_number }}
edit-mode: replace
body: |
:computer: Deploy preview available: ${{ steps.deploy.outputs.url }}${{ inputs.relative_prefix }}
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
/node_modules/
/add-to-docs-project/node_modules/
/add-to-docs-project/index.mjs
build.conf
11 changes: 11 additions & 0 deletions deploy-preview/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM nginx:1.21.6-alpine

COPY ./dist /usr/share/nginx/dist

RUN rm -rf /etc/nginx/sites-enabled && \
rm -rf /etc/nginx/nginx.conf

COPY deploy-preview-files/deploy-preview/nginx.conf /etc/nginx/nginx.conf
COPY build.conf /etc/nginx/build.conf

RUN nginx -t
34 changes: 34 additions & 0 deletions deploy-preview/config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
"Params":
"sitemapExclude": "/"
"build":
"buildStatus":
"enable": false
"disableKinds":
- "robotstxt"
- "rss"
- "sitemap"
- "taxonomy"
- "term"
"disableLanguages":
- "de"
- "fr"
- "es"
- "pt-br"
- "zh-cn"
- "ja"
"enableGitInfo": false
"outputs":
"home":
[
"HTML",
"Header",
"Footer",
"head",
"styles",
"ssi_footer",
"scripts",
"Assets",
]
"section":
- "HTML"
- "JSON"
105 changes: 105 additions & 0 deletions deploy-preview/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
worker_processes 5;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
worker_rlimit_nofile 8192;

events {
worker_connections 4096;
}

http {

sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;

include /etc/nginx/mime.types;
default_type application/octet-stream;

ssl_protocols TLSv1 TLSv1.1 TLSv1.2 TLSv1.3; # Dropping SSLv3, ref: POODLE
ssl_prefer_server_ciphers on;

access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;

gzip on;

gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;

server {
absolute_redirect off;

listen 80;

include /etc/nginx/build.conf;

add_header "X-UA-Compatible" "IE=Edge,chrome=1";
add_header "Strict-Transport-Security" "max-age=31536000; includeSubDomains; preload";
add_header "Referrer-Policy" "origin-when-cross-origin";


add_header Cache-Control "public, max-age=0, must-revalidate";
add_header X-Frame-Options "DENY";

add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';

error_page 404 /404.html;
error_page 403 /404.html; # show 404 instead of 403 when directory exists but index.html does not
location = /404.html {
root /usr/share/nginx/dist/;
internal;
}

# move assets to a different layer to prevent docker cache invalidation
# https://regex101.com/r/M7HrFY/1
location ~* ^/static/(app.min.css|app.css.map|shared.min.css|shared.css.map|.*.json|.*.html|.*.js|lastmod.csv)$ {
alias /usr/share/nginx/assets/$1;
}

location / {
alias /usr/share/nginx/dist/;
}

location /static {
proxy_pass https://grafana.com/static;
}

location /media {
proxy_pass https://grafana.com/media;
}

location /api {
proxy_pass https://grafana.com/api;
}

location ~ ^/connect(.*)$ {

proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;

proxy_ssl_server_name on;
resolver 8.8.8.8 8.8.4.4 ipv6=off;
resolver_timeout 5s;
set $faro "faro-collector-prod-us-central-0.grafana.net";

proxy_pass https://$faro/collect$1;
}


location /healthz {
return 200 'ok';
add_header Content-Type text/plain;
}
}
}