test(corpus): add public real yaml seeds

Vendor the pinned public YAML seeds used by the real-corpus and Yams differential gates.
This commit is contained in:
Mihaela Mihaljevic 2026-06-06 08:24:12 +02:00
parent b9215d4015
commit ca96772207
104 changed files with 194567 additions and 0 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,24 @@
# This is an example of a typical ApplicationSet which uses the cluster generator.
# An ApplicationSet is comprised with two stanzas:
# - spec.generator - producer of a list of values supplied as arguments to an app template
# - spec.template - an application template, which has been parameterized
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: guestbook
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
- clusters: {}
template:
metadata:
name: '{{.name}}-guestbook'
spec:
source:
repoURL: https://github.com/infra-team/cluster-deployments.git
targetRevision: HEAD
chart: guestbook
destination:
server: '{{.server}}'
namespace: guestbook

View File

@ -0,0 +1 @@
# Blank values.yaml

View File

@ -0,0 +1,10 @@
services:
web:
build:
context: angular
target: builder
ports:
- 4200:4200
volumes:
- ./angular:/project
- /project/node_modules

View File

@ -0,0 +1,9 @@
services:
web:
build:
context: app
target: builder
ports:
- '80:80'
volumes:
- ./app:/var/www/html/

View File

@ -0,0 +1,22 @@
services:
web:
build: app/aspnetapp
ports:
- 80:80
db:
environment:
ACCEPT_EULA: "Y"
SA_PASSWORD: example_123
# mssql server image isn't available for arm64 architecture, so we use azure-sql instead
image: mcr.microsoft.com/azure-sql-edge:1.0.4
# If you really want to use MS SQL Server, uncomment the following line
#image: mcr.microsoft.com/mssql/server
restart: always
healthcheck:
test: ["CMD-SHELL", "/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P example_123 -Q 'SELECT 1' || exit 1"]
interval: 10s
retries: 10
start_period: 10s
timeout: 3s

View File

@ -0,0 +1,7 @@
services:
web:
build:
context: app
target: builder
ports:
- '8000:8000'

View File

@ -0,0 +1,48 @@
services:
elasticsearch:
image: elasticsearch:7.16.1
container_name: es
environment:
discovery.type: single-node
ES_JAVA_OPTS: "-Xms512m -Xmx512m"
ports:
- "9200:9200"
- "9300:9300"
healthcheck:
test: ["CMD-SHELL", "curl --silent --fail localhost:9200/_cluster/health || exit 1"]
interval: 10s
timeout: 10s
retries: 3
networks:
- elastic
logstash:
image: logstash:7.16.1
container_name: log
environment:
discovery.seed_hosts: logstash
LS_JAVA_OPTS: "-Xms512m -Xmx512m"
volumes:
- ./logstash/pipeline/logstash-nginx.config:/usr/share/logstash/pipeline/logstash-nginx.config
- ./logstash/nginx.log:/home/nginx.log
ports:
- "5000:5000/tcp"
- "5000:5000/udp"
- "5044:5044"
- "9600:9600"
depends_on:
- elasticsearch
networks:
- elastic
command: logstash -f /usr/share/logstash/pipeline/logstash-nginx.config
kibana:
image: kibana:7.16.1
container_name: kib
ports:
- "5601:5601"
depends_on:
- elasticsearch
networks:
- elastic
networks:
elastic:
driver: bridge

View File

@ -0,0 +1,11 @@
services:
api:
build:
context: .
target: builder
container_name: fastapi-application
environment:
PORT: 8000
ports:
- '8000:8000'
restart: "no"

View File

@ -0,0 +1,10 @@
services:
web:
build:
context: app
target: builder
# flask requires SIGINT to stop gracefully
# (default stop signal from Compose is SIGTERM)
stop_signal: SIGINT
ports:
- '8000:8000'

View File

@ -0,0 +1,18 @@
services:
redis:
image: redislabs/redismod
ports:
- '6379:6379'
web:
build:
context: .
target: builder
# flask requires SIGINT to stop gracefully
# (default stop signal from Compose is SIGTERM)
stop_signal: SIGINT
ports:
- '8000:8000'
volumes:
- .:/code
depends_on:
- redis

View File

@ -0,0 +1,31 @@
services:
gitea:
image: gitea/gitea:latest
environment:
- DB_TYPE=postgres
- DB_HOST=db:5432
- DB_NAME=gitea
- DB_USER=gitea
- DB_PASSWD=gitea
restart: always
volumes:
- git_data:/data
ports:
- 3000:3000
db:
image: postgres:alpine
environment:
- POSTGRES_USER=gitea
- POSTGRES_PASSWORD=gitea
- POSTGRES_DB=gitea
restart: always
volumes:
- db_data:/var/lib/postgresql/data
expose:
- 5432
volumes:
db_data:
git_data:

View File

@ -0,0 +1,13 @@
services:
minecraft:
image: itzg/minecraft-server
ports:
- "25565:25565"
environment:
EULA: "TRUE"
deploy:
resources:
limits:
memory: 1.5G
volumes:
- "~/minecraft_data:/data"

View File

@ -0,0 +1,27 @@
services:
nc:
image: nextcloud:apache
environment:
- POSTGRES_HOST=db
- POSTGRES_PASSWORD=nextcloud
- POSTGRES_DB=nextcloud
- POSTGRES_USER=nextcloud
ports:
- 80:80
restart: always
volumes:
- nc_data:/var/www/html
db:
image: postgres:alpine
environment:
- POSTGRES_PASSWORD=nextcloud
- POSTGRES_DB=nextcloud
- POSTGRES_USER=nextcloud
restart: always
volumes:
- db_data:/var/lib/postgresql/data
expose:
- 5432
volumes:
db_data:
nc_data:

View File

@ -0,0 +1,45 @@
services:
nc:
image: nextcloud:apache
restart: always
ports:
- 80:80
volumes:
- nc_data:/var/www/html
networks:
- redisnet
- dbnet
environment:
- REDIS_HOST=redis
- MYSQL_HOST=db
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
- MYSQL_PASSWORD=nextcloud
redis:
image: redis:alpine
restart: always
networks:
- redisnet
expose:
- 6379
db:
image: mariadb:10.5
command: --transaction-isolation=READ-COMMITTED --binlog-format=ROW
restart: always
volumes:
- db_data:/var/lib/mysql
networks:
- dbnet
environment:
- MYSQL_DATABASE=nextcloud
- MYSQL_USER=nextcloud
- MYSQL_ROOT_PASSWORD=nextcloud
- MYSQL_PASSWORD=nextcloud
expose:
- 3306
volumes:
db_data:
nc_data:
networks:
dbnet:
redisnet:

View File

@ -0,0 +1,46 @@
services:
backend:
build:
context: backend
restart: always
secrets:
- db-password
depends_on:
db:
condition: service_healthy
environment:
- ASPNETCORE_URLS=http://+:8000
db:
# We use a mariadb image which supports both amd64 & arm64 architecture
image: mariadb:10-focal
# If you really want to use MySQL, uncomment the following line
#image: mysql:8
command: '--default-authentication-plugin=mysql_native_password'
restart: always
healthcheck:
test: ['CMD-SHELL', 'mysqladmin ping -h 127.0.0.1 --password="$$(cat /run/secrets/db-password)" --silent']
interval: 3s
retries: 5
start_period: 30s
secrets:
- db-password
volumes:
- db-data:/var/lib/mysql
environment:
- MYSQL_DATABASE=example
- MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db-password
proxy:
build: proxy
ports:
- 80:80
depends_on:
- backend
volumes:
db-data:
secrets:
db-password:
file: db/password.txt

View File

@ -0,0 +1,29 @@
services:
web:
image: nginx
volumes:
- ./nginx/nginx.conf:/tmp/nginx.conf
environment:
- FLASK_SERVER_ADDR=backend:9091
command: /bin/bash -c "envsubst < /tmp/nginx.conf > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
ports:
- 80:80
depends_on:
- backend
backend:
build:
context: flask
target: builder
# flask requires SIGINT to stop gracefully
# (default stop signal from Compose is SIGTERM)
stop_signal: SIGINT
environment:
- FLASK_SERVER_PORT=9091
volumes:
- ./flask:/src
depends_on:
- mongo
mongo:
image: mongo

View File

@ -0,0 +1,62 @@
services:
db:
# We use a mariadb image which supports both amd64 & arm64 architecture
image: mariadb:10-focal
# If you really want to use MySQL, uncomment the following line
#image: mysql:8
command: '--default-authentication-plugin=mysql_native_password'
restart: always
healthcheck:
test: ['CMD-SHELL', 'mysqladmin ping -h 127.0.0.1 --password="$$(cat /run/secrets/db-password)" --silent']
interval: 3s
retries: 5
start_period: 30s
secrets:
- db-password
volumes:
- db-data:/var/lib/mysql
networks:
- backnet
environment:
- MYSQL_DATABASE=example
- MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db-password
expose:
- 3306
- 33060
backend:
build:
context: backend
target: builder
restart: always
secrets:
- db-password
ports:
- 8000:8000
networks:
- backnet
- frontnet
depends_on:
db:
condition: service_healthy
proxy:
build: proxy
restart: always
ports:
- 80:80
depends_on:
- backend
networks:
- frontnet
volumes:
db-data:
secrets:
db-password:
file: db/password.txt
networks:
backnet:
frontnet:

View File

@ -0,0 +1,17 @@
services:
proxy:
image: nginx
volumes:
- type: bind
source: ./proxy/nginx.conf
target: /etc/nginx/conf.d/default.conf
read_only: true
ports:
- 80:80
depends_on:
- backend
backend:
build:
context: backend
target: builder

View File

@ -0,0 +1,51 @@
services:
backend:
build:
context: backend
target: builder
secrets:
- db-password
depends_on:
db:
condition: service_healthy
db:
# We use a mariadb image which supports both amd64 & arm64 architecture
image: mariadb:10-focal
# If you really want to use MySQL, uncomment the following line
#image: mysql:8
command: '--default-authentication-plugin=mysql_native_password'
restart: always
healthcheck:
test: ['CMD-SHELL', 'mysqladmin ping -h 127.0.0.1 --password="$$(cat /run/secrets/db-password)" --silent']
interval: 3s
retries: 5
start_period: 30s
secrets:
- db-password
volumes:
- db-data:/var/lib/mysql
environment:
- MYSQL_DATABASE=example
- MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db-password
expose:
- 3306
proxy:
image: nginx
volumes:
- type: bind
source: ./proxy/nginx.conf
target: /etc/nginx/conf.d/default.conf
read_only: true
ports:
- 80:80
depends_on:
- backend
volumes:
db-data:
secrets:
db-password:
file: db/password.txt

View File

@ -0,0 +1,48 @@
services:
backend:
build:
context: backend
target: builder
secrets:
- db-password
depends_on:
db:
condition: service_healthy
db:
image: postgres
restart: always
user: postgres
secrets:
- db-password
volumes:
- db-data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=example
- POSTGRES_PASSWORD_FILE=/run/secrets/db-password
expose:
- 5432
healthcheck:
test: [ "CMD", "pg_isready" ]
interval: 10s
timeout: 5s
retries: 5
proxy:
image: nginx
volumes:
- type: bind
source: ./proxy/nginx.conf
target: /etc/nginx/conf.d/default.conf
read_only: true
ports:
- 80:80
depends_on:
- backend
volumes:
db-data:
secrets:
db-password:
file: db/password.txt

View File

@ -0,0 +1,27 @@
services:
redis:
image: 'redislabs/redismod'
ports:
- '6379:6379'
web1:
restart: on-failure
build: ./web
hostname: web1
ports:
- '81:5000'
web2:
restart: on-failure
build: ./web
hostname: web2
ports:
- '82:5000'
nginx:
build: ./nginx
ports:
- '80:80'
depends_on:
- web1
- web2

View File

@ -0,0 +1,29 @@
services:
nginx-proxy:
build: nginx
restart: always
volumes:
- ./nginx/default.conf:/tmp/default.conf
environment:
- FLASK_SERVER_ADDR=flask-app:8000
ports:
- "80:80"
depends_on:
- flask-app
healthcheck:
test: ["CMD-SHELL", "curl --silent --fail localhost:80/health-check || exit 1"]
interval: 10s
timeout: 10s
retries: 3
command: /app/start.sh
flask-app:
build: flask
restart: always
ports:
- '8000:8000'
healthcheck:
test: ["CMD-SHELL", "curl --silent --fail localhost:8000/flask-health-check || exit 1"]
interval: 10s
timeout: 10s
retries: 3
command: gunicorn -w 3 -t 60 -b 0.0.0.0:8000 app:app

View File

@ -0,0 +1,55 @@
version: '3.7'
services:
cloudflared:
image: visibilityspots/cloudflared
container_name: cloudflared
ports:
- "5054:5054/tcp"
- "5054:5054/udp"
environment:
- TZ=${TIMEZONE}
- PORT=5054
- ADDRESS=0.0.0.0
restart: always
networks:
dns-net:
ipv4_address: 172.20.0.2
pihole:
container_name: pihole
image: pihole/pihole:latest
ports:
- "53:53/tcp"
- "53:53/udp"
- "67:67/udp"
- "8080:80/tcp"
- "8443:443/tcp"
environment:
- TZ=${TIMEZONE}
- PIHOLE_DNS_=172.20.0.2#5054;1.1.1.1 # referencing by name results in "Invalid IP detected in PIHOLE_DNS_: cloudflared#5054"
- WEBPASSWORD=${PIHOLE_PW}
- REV_SERVER=true
- REV_SERVER_TARGET=${PIHOLE_ROUTER_IP}
- REV_SERVER_DOMAIN=${PIHOLE_NETWORK_DOMAIN}
- REV_SERVER_CIDR=${PIHOLE_REVERSE_DNS}
- ServerIP=${PIHOLE_HOST_IP}
- ServerIPv6=${PIHOLE_HOST_IPV6}
#dns:
#- 127.0.0.1 # "Sets your container's resolve settings to localhost so it can resolve DHCP hostnames [...]" - github.com/pi-hole/docker-pi-hole
#- 1.1.1.1 # Backup server
volumes: # store your data between container upgrades
- "/etc/pihole/:/etc/pihole/"
- "/etc/dnsmasq.d/:/etc/dnsmasq.d/"
cap_add:
- NET_ADMIN # Recommended but not required (DHCP needs NET_ADMIN) https://github.com/pi-hole/docker-pi-hole#note-on-capabilities
depends_on:
- "cloudflared"
restart: always
networks:
- dns-net
networks:
dns-net:
ipam:
config:
- subnet: 172.20.0.0/24

View File

@ -0,0 +1,10 @@
services:
plex:
image: linuxserver/plex
container_name: plex
network_mode: host
environment:
- VERSION=docker
restart: always
volumes:
- ${PLEX_MEDIA_PATH}:/media/

View File

@ -0,0 +1,14 @@
services:
portainer:
image: portainer/portainer-ce:alpine
container_name: portainer
command: -H unix:///var/run/docker.sock
ports:
- "9000:9000"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
- "portainer_data:/data"
restart: always
volumes:
portainer_data:

View File

@ -0,0 +1,21 @@
services:
postgres:
container_name: postgres
image: postgres:latest
environment:
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PW}
- POSTGRES_DB=${POSTGRES_DB} #optional (specify default database instead of $POSTGRES_DB)
ports:
- "5432:5432"
restart: always
pgadmin:
container_name: pgadmin
image: dpage/pgadmin4:latest
environment:
- PGADMIN_DEFAULT_EMAIL=${PGADMIN_MAIL}
- PGADMIN_DEFAULT_PASSWORD=${PGADMIN_PW}
ports:
- "5050:80"
restart: always

View File

@ -0,0 +1,25 @@
services:
prometheus:
image: prom/prometheus
container_name: prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
ports:
- 9090:9090
restart: unless-stopped
volumes:
- ./prometheus:/etc/prometheus
- prom_data:/prometheus
grafana:
image: grafana/grafana
container_name: grafana
ports:
- 3000:3000
restart: unless-stopped
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=grafana
volumes:
- ./grafana:/etc/grafana/provisioning/datasources
volumes:
prom_data:

View File

@ -0,0 +1,47 @@
services:
frontend:
build:
context: frontend
target: development
ports:
- 3000:3000
stdin_open: true
volumes:
- ./frontend:/usr/src/app
- /usr/src/app/node_modules
restart: always
networks:
- react-express
depends_on:
- backend
backend:
restart: always
build:
context: backend
target: development
volumes:
- ./backend:/usr/src/app
- /usr/src/app/node_modules
depends_on:
- mongo
networks:
- express-mongo
- react-express
expose:
- 3000
mongo:
restart: always
image: mongo:4.2.0
volumes:
- mongo_data:/data/db
networks:
- express-mongo
expose:
- 27017
networks:
react-express:
express-mongo:
volumes:
mongo_data:

View File

@ -0,0 +1,68 @@
services:
backend:
build:
args:
- NODE_ENV=development
context: backend
target: development
command: npm run start-watch
environment:
- DATABASE_DB=example
- DATABASE_USER=root
- DATABASE_PASSWORD=/run/secrets/db-password
- DATABASE_HOST=db
- NODE_ENV=development
ports:
- 80:80
- 9229:9229
- 9230:9230
secrets:
- db-password
volumes:
- ./backend/src:/code/src:ro
- ./backend/package.json:/code/package.json
- ./backend/package-lock.json:/code/package-lock.json
- back-notused:/opt/app/node_modules
networks:
- public
- private
depends_on:
- db
db:
# We use a mariadb image which supports both amd64 & arm64 architecture
image: mariadb:10.6.4-focal
# If you really want to use MySQL, uncomment the following line
#image: mysql:8.0.27
command: '--default-authentication-plugin=mysql_native_password'
restart: always
secrets:
- db-password
volumes:
- db-data:/var/lib/mysql
networks:
- private
environment:
- MYSQL_DATABASE=example
- MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db-password
frontend:
build:
context: frontend
target: development
ports:
- 3000:3000
volumes:
- ./frontend/src:/code/src
- /code/node_modules
networks:
- public
depends_on:
- backend
networks:
public:
private:
volumes:
back-notused:
db-data:
secrets:
db-password:
file: db/password.txt

View File

@ -0,0 +1,58 @@
services:
backend:
build: backend
restart: always
secrets:
- db-password
environment:
MYSQL_HOST: db
networks:
- react-spring
- spring-mysql
depends_on:
db:
condition: service_healthy
db:
# We use a mariadb image which supports both amd64 & arm64 architecture
image: mariadb:10.6.4-focal
# If you really want to use MySQL, uncomment the following line
#image: mysql:8.0.19
environment:
- MYSQL_DATABASE=example
- MYSQL_ROOT_PASSWORD_FILE=/run/secrets/db-password
restart: always
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "--silent"]
interval: 3s
retries: 5
start_period: 30s
secrets:
- db-password
volumes:
- db-data:/var/lib/mysql
networks:
- spring-mysql
frontend:
build:
context: frontend
target: development
ports:
- 3000:3000
volumes:
- ./frontend/src:/code/src
- /project/node_modules
networks:
- react-spring
depends_on:
- backend
expose:
- 3306
- 33060
volumes:
db-data: {}
secrets:
db-password:
file: db/password.txt
networks:
react-spring: {}
spring-mysql: {}

View File

@ -0,0 +1,7 @@
services:
frontend:
build:
context: .
container_name: frontend
ports:
- "80:80"

View File

@ -0,0 +1,52 @@
name: react-rust-postgres
services:
frontend:
build:
context: frontend
target: development
networks:
- client-side
ports:
- 3000:3000
volumes:
- ./frontend/src:/code/src:ro
backend:
build:
context: backend
target: development
environment:
- ADDRESS=0.0.0.0:8000
- RUST_LOG=debug
- PG_DBNAME=postgres
- PG_HOST=db
- PG_USER=postgres
- PG_PASSWORD=mysecretpassword
networks:
- client-side
- server-side
volumes:
- ./backend/src:/code/src
- backend-cache:/code/target
depends_on:
- db
db:
image: postgres:12-alpine
restart: always
environment:
- POSTGRES_PASSWORD=mysecretpassword
networks:
- server-side
ports:
- 5432:5432
volumes:
- db-data:/var/lib/postgresql/data
networks:
client-side: {}
server-side: {}
volumes:
backend-cache: {}
db-data: {}

View File

@ -0,0 +1,40 @@
# Copyright Broadcom, Inc. All Rights Reserved.
# SPDX-License-Identifier: APACHE-2.0
annotations:
images: |
- name: apache
image: docker.io/bitnami/apache:2.4.65-debian-12-r2
- name: apache-exporter
image: docker.io/bitnami/apache-exporter:1.0.10-debian-12-r55
- name: git
image: docker.io/bitnami/git:2.51.0-debian-12-r0
licenses: Apache-2.0
tanzuCategory: service
apiVersion: v2
appVersion: 2.4.65
dependencies:
- name: common
repository: oci://registry-1.docker.io/bitnamicharts
tags:
- bitnami-common
version: 2.x.x
description: Apache HTTP Server is an open-source HTTP server. The goal of this project
is to provide a secure, efficient and extensible server that provides HTTP services
in sync with the current HTTP standards.
home: https://bitnami.com
icon: https://dyltqmyl993wv.cloudfront.net/assets/stacks/apache/img/apache-stack-220x234.png
keywords:
- apache
- http
- https
- www
- web
- reverse proxy
maintainers:
- name: Broadcom, Inc. All Rights Reserved.
url: https://github.com/bitnami/charts
name: apache
sources:
- https://github.com/bitnami/charts/tree/main/bitnami/apache
version: 11.4.30

View File

@ -0,0 +1,820 @@
# Copyright Broadcom, Inc. All Rights Reserved.
# SPDX-License-Identifier: APACHE-2.0
## @section Global parameters
## Global Docker image parameters
## Please, note that this will override the image parameters, including dependencies, configured to use the global value
## Current available global Docker image parameters: imageRegistry, imagePullSecrets and storageClass
## @param global.imageRegistry Global Docker image registry
## @param global.imagePullSecrets Global Docker registry secret names as an array
## @param global.defaultStorageClass Global default StorageClass for Persistent Volume(s)
## @param global.storageClass DEPRECATED: use global.defaultStorageClass instead
##
global:
imageRegistry: ""
## E.g.
## imagePullSecrets:
## - myRegistryKeySecretName
##
imagePullSecrets: []
defaultStorageClass: ""
storageClass: ""
## Compatibility adaptations for Kubernetes platforms
##
compatibility:
## Compatibility adaptations for Openshift
##
openshift:
## @param global.compatibility.openshift.adaptSecurityContext Adapt the securityContext sections of the deployment to make them compatible with Openshift restricted-v2 SCC: remove runAsUser, runAsGroup and fsGroup and let the platform use their allowed default IDs. Possible values: auto (apply if the detected running cluster is Openshift), force (perform the adaptation always), disabled (do not perform adaptation)
##
adaptSecurityContext: auto
## Security parameters
##
security:
## @param global.security.allowInsecureImages By default, this chart verifies that the original container images that were designed, tested, and validated are used. This option makes the chart skip the verification step and proceed
##
allowInsecureImages: false
## @section Common parameters
## @param kubeVersion Override Kubernetes version
##
kubeVersion: ""
## @param nameOverride String to partially override common.names.fullname
##
nameOverride: ""
## @param fullnameOverride String to fully override common.names.fullname
##
fullnameOverride: ""
## @param commonLabels Labels to add to all deployed objects
##
commonLabels: {}
## @param commonAnnotations Annotations to add to all deployed objects
##
commonAnnotations: {}
## @param extraDeploy Array of extra objects to deploy with the release
##
extraDeploy: []
## @section Apache parameters
## Bitnami Apache image
## ref: https://hub.docker.com/r/bitnami/apache/tags/
## @param image.registry [default: REGISTRY_NAME] Apache image registry
## @param image.repository [default: REPOSITORY_NAME/apache] Apache image repository
## @skip image.tag Apache image tag (immutable tags are recommended)
## @param image.digest Apache image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag
## @param image.pullPolicy Apache image pull policy
## @param image.pullSecrets Apache image pull secrets
## @param image.debug Enable image debug mode
##
image:
registry: docker.io
repository: bitnami/apache
tag: 2.4.65-debian-12-r2
digest: ""
## Specify a imagePullPolicy
## ref: https://kubernetes.io/docs/concepts/containers/images/#pre-pulled-images
##
pullPolicy: IfNotPresent
## Optionally specify an array of imagePullSecrets.
## Secrets must be manually created in the namespace.
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
## e.g:
## pullSecrets:
## - myRegistryKeySecretName
##
pullSecrets: []
## Enable debug mode
##
debug: false
## Bitnami Git image version
## ref: https://hub.docker.com/r/bitnami/git/tags/
## @param git.registry [default: REGISTRY_NAME] Git image registry
## @param git.repository [default: REPOSITORY_NAME/git] Git image name
## @skip git.tag Git image tag (immutable tags are recommended)
## @param git.digest Git image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag
## @param git.pullPolicy Git image pull policy
## @param git.pullSecrets Specify docker-registry secret names as an array
##
git:
registry: docker.io
repository: bitnami/git
tag: 2.51.0-debian-12-r0
digest: ""
pullPolicy: IfNotPresent
## Optionally specify an array of imagePullSecrets.
## Secrets must be manually created in the namespace.
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
## e.g:
## pullSecrets:
## - myRegistryKeySecretName
##
pullSecrets: []
## @param replicaCount Number of replicas of the Apache deployment
##
replicaCount: 1
## @param revisionHistoryLimit The number of old history to retain to allow rollback
##
revisionHistoryLimit: 10
## @param podAffinityPreset Pod affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard`
## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity
##
podAffinityPreset: ""
## @param podAntiAffinityPreset Pod anti-affinity preset. Ignored if `affinity` is set. Allowed values: `soft` or `hard`
## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity
##
podAntiAffinityPreset: soft
## Node affinity preset
## Ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity
##
nodeAffinityPreset:
## @param nodeAffinityPreset.type Node affinity preset type. Ignored if `affinity` is set. Allowed values: `soft` or `hard`
##
type: ""
## @param nodeAffinityPreset.key Node label key to match. Ignored if `affinity` is set
##
key: ""
## @param nodeAffinityPreset.values Node label values to match. Ignored if `affinity` is set
## E.g.
## values:
## - e2e-az1
## - e2e-az2
##
values: []
## @param affinity Affinity for pod assignment
## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
## NOTE: podAffinityPreset, podAntiAffinityPreset, and nodeAffinityPreset will be ignored when it's set
##
affinity: {}
## @param nodeSelector Node labels for pod assignment
## ref: https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/
##
nodeSelector: {}
## @param tolerations Tolerations for pod assignment
## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
##
tolerations: []
## @param topologySpreadConstraints Topology Spread Constraints for pod assignment spread across your cluster among failure-domains. Evaluated as a template
## Ref: https://kubernetes.io/docs/concepts/workloads/pods/pod-topology-spread-constraints/#spread-constraints-for-pods
##
topologySpreadConstraints: []
## @param extraPodSpec Optionally specify extra PodSpec
##
extraPodSpec: {}
## Get the server static content from a git repository
## @param cloneHtdocsFromGit.enabled Get the server static content from a git repository
## @param cloneHtdocsFromGit.repository Repository to clone static content from
## @param cloneHtdocsFromGit.branch Branch inside the git repository
## @param cloneHtdocsFromGit.enableAutoRefresh Enables an automatic git pull with a sidecar container
## @param cloneHtdocsFromGit.interval Interval for sidecar container pull from the repository
## @param cloneHtdocsFromGit.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if cloneHtdocsFromGit.resources is set (cloneHtdocsFromGit.resources is recommended for production).
## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15
## @param cloneHtdocsFromGit.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads)
## Example:
## resources:
## requests:
## cpu: 2
## memory: 512Mi
## limits:
## cpu: 3
## memory: 1024Mi
## @param cloneHtdocsFromGit.extraVolumeMounts Add extra volume mounts for the GIT containers
##
cloneHtdocsFromGit:
enabled: false
repository: ""
branch: ""
enableAutoRefresh: true
interval: 60
resourcesPreset: "nano"
resources: {}
## Useful to mount keys to connect through ssh. (normally used with extraVolumes)
## E.g:
## extraVolumeMounts:
## - name: ssh-dir
## mountPath: /root/.ssh/
##
extraVolumeMounts: []
## @param htdocsConfigMap Name of a config map with the server static content
##
htdocsConfigMap: ""
## @param htdocsPVC Name of a PVC with the server static content
##
htdocsPVC: ""
## @param vhostsConfigMap Name of a config map with the virtual hosts content
##
vhostsConfigMap: ""
## @param httpdConfConfigMap Name of a config map with the httpd.conf file contents
##
httpdConfConfigMap: ""
## @param podLabels Extra labels for Apache pods
## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
##
podLabels: {}
## @param podAnnotations Pod annotations
## ref: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations/
##
podAnnotations: {}
## @param automountServiceAccountToken Mount Service Account token in pod
##
automountServiceAccountToken: false
## @param hostAliases [array] Add deployment host aliases
## https://kubernetes.io/docs/concepts/services-networking/add-entries-to-pod-etc-hosts-with-host-aliases/
##
hostAliases:
## Necessary for apache-exporter to work
##
- ip: "127.0.0.1"
hostnames:
- "status.localhost"
## @param priorityClassName Apache Server pods' priorityClassName
##
priorityClassName: ""
## @param schedulerName Name of the k8s scheduler (other than default)
## ref: https://kubernetes.io/docs/tasks/administer-cluster/configure-multiple-schedulers/
##
schedulerName: ""
## Configure Pods Security Context
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
## @param podSecurityContext.enabled Enabled Apache Server pods' Security Context
## @param podSecurityContext.fsGroupChangePolicy Set filesystem group change policy
## @param podSecurityContext.sysctls Set kernel settings using the sysctl interface
## @param podSecurityContext.supplementalGroups Set filesystem extra groups
## @param podSecurityContext.fsGroup Set Apache Server pod's Security Context fsGroup
##
podSecurityContext:
enabled: true
fsGroupChangePolicy: Always
sysctls: []
supplementalGroups: []
fsGroup: 1001
## Configure Container Security Context
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/security-context/#set-the-security-context-for-a-pod
## @param containerSecurityContext.enabled Enabled Apache Server containers' Security Context
## @param containerSecurityContext.seLinuxOptions [object,nullable] Set SELinux options in container
## @param containerSecurityContext.runAsUser Set Apache Server containers' Security Context runAsUser
## @param containerSecurityContext.runAsGroup Set Apache Server containers' Security Context runAsGroup
## @param containerSecurityContext.runAsNonRoot Set Controller container's Security Context runAsNonRoot
## @param containerSecurityContext.privileged Set primary container's Security Context privileged
## @param containerSecurityContext.allowPrivilegeEscalation Set primary container's Security Context allowPrivilegeEscalation
## @param containerSecurityContext.readOnlyRootFilesystem Set primary container's Security Context readOnlyRootFilesystem
## @param containerSecurityContext.capabilities.drop List of capabilities to be dropped
## @param containerSecurityContext.seccompProfile.type Set container's Security Context seccomp profile
##
containerSecurityContext:
enabled: true
seLinuxOptions: {}
runAsUser: 1001
runAsGroup: 1001
runAsNonRoot: true
privileged: false
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop: ["ALL"]
seccompProfile:
type: "RuntimeDefault"
## @param command Override default container command (useful when using custom images)
##
command: []
## @param args Override default container args (useful when using custom images)
##
args: []
## @param lifecycleHooks for the Apache server container(s) to automate configuration before or after startup
##
lifecycleHooks: {}
## Apache pods' resource requests and limits
## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/
## We usually recommend not to specify default resources and to leave this as a conscious
## choice for the user. This also increases chances charts run on environments with little
## resources, such as Minikube. If you do want to specify resources, uncomment the following
## lines, adjust them as necessary, and remove the curly braces after 'resources:'.
## @param resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if resources is set (resources is recommended for production).
## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15
##
resourcesPreset: "nano"
## @param resources Set container requests and limits for different resources like CPU or memory (essential for production workloads)
## Example:
## resources:
## requests:
## cpu: 2
## memory: 512Mi
## limits:
## cpu: 3
## memory: 1024Mi
##
resources: {}
## Configure extra options for containers' liveness and readiness probes
## Configure extra options for Apache server containers' liveness, readiness and startup probes
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-probes/#configure-probes)
## @param startupProbe.enabled Enable startupProbe
## @param startupProbe.path Path to access on the HTTP server
## @param startupProbe.port Port for startupProbe
## @param startupProbe.initialDelaySeconds Initial delay seconds for startupProbe
## @param startupProbe.periodSeconds Period seconds for startupProbe
## @param startupProbe.timeoutSeconds Timeout seconds for startupProbe
## @param startupProbe.failureThreshold Failure threshold for startupProbe
## @param startupProbe.successThreshold Success threshold for startupProbe
##
startupProbe:
enabled: false
path: "/"
port: http
initialDelaySeconds: 180
periodSeconds: 20
timeoutSeconds: 5
failureThreshold: 6
successThreshold: 1
## @param livenessProbe.enabled Enable liveness probe
## @param livenessProbe.port Port for livenessProbe
## @param livenessProbe.initialDelaySeconds Initial delay seconds for livenessProbe
## @param livenessProbe.periodSeconds Period seconds for livenessProbe
## @param livenessProbe.timeoutSeconds Timeout seconds for livenessProbe
## @param livenessProbe.failureThreshold Failure threshold for livenessProbe
## @param livenessProbe.successThreshold Success threshold for livenessProbe
##
livenessProbe:
enabled: true
port: http
initialDelaySeconds: 180
periodSeconds: 20
timeoutSeconds: 5
failureThreshold: 6
successThreshold: 1
## @param readinessProbe.enabled Enable readiness probe
## @param readinessProbe.path Path to access on the HTTP server
## @param readinessProbe.port Port for readinessProbe
## @param readinessProbe.initialDelaySeconds Initial delay seconds for readinessProbe
## @param readinessProbe.periodSeconds Period seconds for readinessProbe
## @param readinessProbe.timeoutSeconds Timeout seconds for readinessProbe
## @param readinessProbe.failureThreshold Failure threshold for readinessProbe
## @param readinessProbe.successThreshold Success threshold for readinessProbe
##
readinessProbe:
enabled: true
path: "/"
port: http
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
failureThreshold: 6
successThreshold: 1
## @param customStartupProbe Custom liveness probe for the Web component
##
customStartupProbe: {}
## @param customLivenessProbe Custom liveness probe for the Web component
##
customLivenessProbe: {}
## @param customReadinessProbe Custom rediness probe for the Web component
##
customReadinessProbe: {}
## @param extraVolumes Array to add extra volumes (evaluated as a template)
##
extraVolumes: []
## @param extraVolumeMounts Array to add extra mounts (normally used with extraVolumes, evaluated as a template)
##
extraVolumeMounts: []
## @param extraEnvVars Array to add extra environment variables
##
extraEnvVars: []
## @param extraEnvVarsCM Name of existing ConfigMap containing extra env vars for Apache server nodes
##
extraEnvVarsCM: ""
## @param extraEnvVarsSecret Name of existing Secret containing extra env vars for Apache server nodes
##
extraEnvVarsSecret: ""
## Apache server container port
## @param containerPorts.http Apache server HTTP container port
## @param containerPorts.https Apache server HTTPS container port
##
containerPorts:
http: 8080
https: 8443
## @param initContainers Add additional init containers to the Apache pods
## Example:
## initContainers:
## - name: your-image-name
## image: your-image
## imagePullPolicy: Always
## ports:
## - name: portname
## containerPort: 1234
##
initContainers: []
## @param sidecars Add additional sidecar containers to the Apache pods
## Example:
## sidecars:
## - name: your-image-name
## image: your-image
## imagePullPolicy: Always
## ports:
## - name: portname
## containerPort: 1234
##
sidecars: []
## @param updateStrategy.type Apache Server deployment strategy type.
## ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy
## e.g:
## updateStrategy:
## type: RollingUpdate
## rollingUpdate:
## maxSurge: 25%
## maxUnavailable: 25%
##
updateStrategy:
type: RollingUpdate
## @section Other Parameters
## Apache Pod Disruption Budget configuration
## ref: https://kubernetes.io/docs/tasks/run-application/configure-pdb/
## @param pdb.create Enable a Pod Disruption Budget creation
## @param pdb.minAvailable Minimum number/percentage of pods that should remain scheduled
## @param pdb.maxUnavailable Maximum number/percentage of pods that may be made unavailable
##
pdb:
create: true
minAvailable: ""
maxUnavailable: ""
## Apache Autoscaling parameters
## ref: https://kubernetes.io/docs/tasks/run-application/horizontal-pod-autoscale/
## @param autoscaling.enabled Enable Horizontal POD autoscaling for Apache
## @param autoscaling.minReplicas Minimum number of Apache replicas
## @param autoscaling.maxReplicas Maximum number of Apache replicas
## @param autoscaling.targetCPU Target CPU utilization percentage
## @param autoscaling.targetMemory Target Memory utilization percentage
##
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 11
targetCPU: 50
targetMemory: 50
## @section Traffic Exposure Parameters
## Apache service parameters
##
service:
## @param service.type Apache Service type
##
type: LoadBalancer
## @param service.ports.http Apache service HTTP port
## @param service.ports.https Apache service HTTPS port
##
ports:
http: 80
https: 443
## Node ports to expose
## @param service.nodePorts.http Node port for HTTP
## @param service.nodePorts.https Node port for HTTPS
##
nodePorts:
http: ""
https: ""
## @param service.clusterIP Apache service Cluster IP
## e.g.:
## clusterIP: None
##
clusterIP: ""
## @param service.loadBalancerIP Apache service Load Balancer IP
## ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-loadbalancer
##
loadBalancerIP: ""
## @param service.loadBalancerSourceRanges Apache service Load Balancer sources
## ref: https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service
## e.g:
## loadBalancerSourceRanges:
## - 10.10.10.0/24
##
loadBalancerSourceRanges: []
## @param service.annotations Additional custom annotations for Apache service
## This can be used to set the LoadBalancer service type to internal only.
## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer
##
annotations: {}
## @param service.externalTrafficPolicy Apache service external traffic policy
## ref https://kubernetes.io/docs/tasks/access-application-cluster/create-external-load-balancer/#preserving-the-client-source-ip
##
externalTrafficPolicy: Cluster
## @param service.extraPorts Extra ports to expose (normally used with the `sidecar` value)
##
extraPorts: []
## @param service.sessionAffinity Session Affinity for Kubernetes service, can be "None" or "ClientIP"
## If "ClientIP", consecutive client requests will be directed to the same mongos Pod
## ref: https://kubernetes.io/docs/concepts/services-networking/service/#virtual-ips-and-service-proxies
##
sessionAffinity: None
## @param service.sessionAffinityConfig Additional settings for the sessionAffinity
## sessionAffinityConfig:
## clientIP:
## timeoutSeconds: 300
##
sessionAffinityConfig: {}
## Network Policies
## Ref: https://kubernetes.io/docs/concepts/services-networking/network-policies/
##
networkPolicy:
## @param networkPolicy.enabled Specifies whether a NetworkPolicy should be created
##
enabled: true
## @param networkPolicy.allowExternal Don't require server label for connections
## The Policy model to apply. When set to false, only pods with the correct
## server label will have network access to the ports server is listening
## on. When true, server will accept connections from any source
## (with the correct destination port).
##
allowExternal: true
## @param networkPolicy.allowExternalEgress Allow the pod to access any range of port and all destinations.
##
allowExternalEgress: true
## @param networkPolicy.extraIngress [array] Add extra ingress rules to the NetworkPolicy
## e.g:
## extraIngress:
## - ports:
## - port: 1234
## from:
## - podSelector:
## - matchLabels:
## - role: frontend
## - podSelector:
## - matchExpressions:
## - key: role
## operator: In
## values:
## - frontend
extraIngress: []
## @param networkPolicy.extraEgress [array] Add extra ingress rules to the NetworkPolicy (ignored if allowExternalEgress=true)
## e.g:
## extraEgress:
## - ports:
## - port: 1234
## to:
## - podSelector:
## - matchLabels:
## - role: frontend
## - podSelector:
## - matchExpressions:
## - key: role
## operator: In
## values:
## - frontend
##
extraEgress: []
## @param networkPolicy.ingressNSMatchLabels [object] Labels to match to allow traffic from other namespaces
## @param networkPolicy.ingressNSPodMatchLabels [object] Pod labels to match to allow traffic from other namespaces
##
ingressNSMatchLabels: {}
ingressNSPodMatchLabels: {}
## Configure the ingress resource that allows you to access the Apache installation
## ref: https://kubernetes.io/docs/concepts/services-networking/ingress/
##
ingress:
## @param ingress.enabled Enable ingress record generation for Apache
##
enabled: false
## @param ingress.selfSigned Create a TLS secret for this ingress record using self-signed certificates generated by Helm
##
selfSigned: false
## @param ingress.pathType Ingress path type
##
pathType: ImplementationSpecific
## @param ingress.apiVersion Force Ingress API version (automatically detected if not set)
##
apiVersion: ""
## @param ingress.ingressClassName IngressClass that will be be used to implement the Ingress (Kubernetes 1.18+)
## IngressClassName is used to reference the IngressClass that should be used to implement this Ingress.
## This is supported in Kubernetes 1.18+ and required if you have more than one IngressClass marked as the default for your cluster .
## ref: https://kubernetes.io/blog/2020/04/02/improvements-to-the-ingress-api-in-kubernetes-1.18/
##
ingressClassName: ""
## @param ingress.hostname Default host for the ingress record
##
hostname: example.local
## @param ingress.path Default path for the ingress record
## NOTE: You may need to set this to '/*' in order to use this with ALB ingress controllers
##
path: /
## @param ingress.annotations Additional annotations for the Ingress resource. To enable certificate autogeneration, place here your cert-manager annotations.
## For a full list of possible ingress annotations, please see
## ref: https://github.com/kubernetes/ingress-nginx/blob/main/docs/user-guide/nginx-configuration/annotations.md
## Use this parameter to set the required annotations for cert-manager, see
## ref: https://cert-manager.io/docs/usage/ingress/#supported-annotations
##
## e.g:
## annotations:
## kubernetes.io/ingress.class: nginx
## cert-manager.io/cluster-issuer: cluster-issuer-name
##
annotations: {}
## @param ingress.tls Enable TLS configuration for the host defined at `ingress.hostname` parameter
## TLS certificates will be retrieved from a TLS secret with name: `{{- printf "%s-tls" .Values.ingress.hostname }}`
## You can:
## - Use the `ingress.secrets` parameter to create this TLS secret
## - Rely on cert-manager to create it by setting the corresponding annotations
## - Rely on Helm to create self-signed certificates by setting `ingress.selfSigned=true`
##
tls: false
## @param ingress.extraHosts An array with additional hostname(s) to be covered with the ingress record
## e.g:
## extraHosts:
## - name: apache.local
## path: /
##
extraHosts: []
## @param ingress.extraPaths An array with additional arbitrary paths that may need to be added to the ingress under the main host
## e.g:
## extraPaths:
## - path: /*
## backend:
## serviceName: ssl-redirect
## servicePort: use-annotation
##
extraPaths: []
## @param ingress.extraTls TLS configuration for additional hostname(s) to be covered with this ingress record
## ref: https://kubernetes.io/docs/concepts/services-networking/ingress/#tls
## e.g:
## extraTls:
## - hosts:
## - apache.local
## secretName: apache.local-tls
##
extraTls: []
## @param ingress.secrets Custom TLS certificates as secrets
## NOTE: 'key' and 'certificate' are expected in PEM format
## NOTE: 'name' should line up with a 'secretName' set further up
## If it is not set and you're using cert-manager, this is unneeded, as it will create a secret for you with valid certificates
## If it is not set and you're NOT using cert-manager either, self-signed certificates will be created valid for 365 days
## It is also possible to create and manage the certificates outside of this helm chart
## Please see README.md for more information
## e.g:
## secrets:
## - name: example.local-tls
## key: |-
## -----BEGIN RSA PRIVATE KEY-----
## ...
## -----END RSA PRIVATE KEY-----
## certificate: |-
## -----BEGIN CERTIFICATE-----
## ...
## -----END CERTIFICATE-----
##
secrets: []
## @param ingress.extraRules Additional rules to be covered with this ingress record
## ref: https://kubernetes.io/docs/concepts/services-networking/ingress/#ingress-rules
## e.g:
## extraRules:
## - host: apache.local
## http:
## path: /
## backend:
## service:
## name: apache-svc
## port:
## name: http
##
extraRules: []
## @section Metrics Parameters
metrics:
## @param metrics.enabled Start a sidecar prometheus exporter to expose Apache metrics
##
enabled: false
## Bitnami Apache Prometheus Exporter image
## ref: https://hub.docker.com/r/bitnami/apache-exporter/tags/
## @param metrics.image.registry [default: REGISTRY_NAME] Apache Exporter image registry
## @param metrics.image.repository [default: REPOSITORY_NAME/apache-exporter] Apache Exporter image repository
## @skip metrics.image.tag Apache Exporter image tag (immutable tags are recommended)
## @param metrics.image.digest Apache Exporter image digest in the way sha256:aa.... Please note this parameter, if set, will override the tag
## @param metrics.image.pullPolicy Apache Exporter image pull policy
## @param metrics.image.pullSecrets Apache Exporter image pull secrets
## @param metrics.image.debug Apache Exporter image debug mode
##
image:
registry: docker.io
repository: bitnami/apache-exporter
tag: 1.0.10-debian-12-r55
digest: ""
pullPolicy: IfNotPresent
## Optionally specify an array of imagePullSecrets.
## Secrets must be manually created in the namespace.
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/
## e.g:
## pullSecrets:
## - myRegistryKeySecretName
##
pullSecrets: []
## Enable debug mode
##
debug: false
## @param metrics.scrapeUri Apache Prometheus Exporter scrape_uri
## Default scrape_uri is 'http://status.localhost:{{ .Values.containerPorts.http }}/server-status/?auto' if this variable is empty.
scrapeUri: ""
## @param metrics.podAnnotations [object] Additional custom annotations for Apache exporter service
##
podAnnotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9117"
## Apache Prometheus exporter resource requests and limits
## ref: https://kubernetes.io/docs/concepts/configuration/manage-compute-resources-container/
## We usually recommend not to specify default resources and to leave this as a conscious
## choice for the user. This also increases chances charts run on environments with little
## resources, such as Minikube. If you do want to specify resources, uncomment the following
## lines, adjust them as necessary, and remove the curly braces after 'resources:'.
## @param metrics.resourcesPreset Set container resources according to one common preset (allowed values: none, nano, micro, small, medium, large, xlarge, 2xlarge). This is ignored if metrics.resources is set (metrics.resources is recommended for production).
## More information: https://github.com/bitnami/charts/blob/main/bitnami/common/templates/_resources.tpl#L15
##
resourcesPreset: "none"
## @param metrics.resources Set container requests and limits for different resources like CPU or memory (essential for production workloads)
## Example:
## resources:
## requests:
## cpu: 2
## memory: 512Mi
## limits:
## cpu: 3
## memory: 1024Mi
##
resources: {}
## @param metrics.containerPort Apache Prometheus Exporter container port
##
containerPort: 9141
## Prometheus exporter service parameters
service:
## @param metrics.service.port Metrics service port
##
port: 9117
## @param metrics.service.annotations [object] Additional custom annotations for Metrics service
##
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "{{ .Values.metrics.service.port }}"
## Prometheus Operator PodMonitor configuration
##
serviceMonitor:
## @param metrics.serviceMonitor.enabled if `true`, creates a Prometheus Operator PodMonitor (also requires `metrics.enabled` to be `true`)
##
enabled: false
## @param metrics.serviceMonitor.namespace Namespace for the PodMonitor Resource (defaults to the Release Namespace)
##
namespace: ""
## @param metrics.serviceMonitor.interval Interval at which metrics should be scraped.
## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#endpoint
## e.g:
## interval: 10s
##
interval: ""
## @param metrics.serviceMonitor.scrapeTimeout Timeout after which the scrape is ended
## ref: https://github.com/coreos/prometheus-operator/blob/master/Documentation/api.md#endpoint
## e.g:
## scrapeTimeout: 10s
##
scrapeTimeout: ""
## @param metrics.serviceMonitor.labels Labels that can be used so PodMonitor will be discovered by Prometheus
##
labels: {}
## @param metrics.serviceMonitor.relabelings RelabelConfigs to apply to samples before scraping
##
relabelings: []
## @param metrics.serviceMonitor.metricRelabelings MetricRelabelConfigs to apply to samples before ingestion
##
metricRelabelings: []
## Prometheus Operator PrometheusRule configuration
##
prometheusRule:
## @param metrics.prometheusRule.enabled if `true`, creates a Prometheus Operator PrometheusRule (also requires `metrics.enabled` to be `true` and `metrics.prometheusRule.rules`)
##
enabled: false
## @param metrics.prometheusRule.namespace Namespace for the PrometheusRule Resource (defaults to the Release Namespace)
##
namespace: ""
## @param metrics.prometheusRule.labels Labels that can be used so PrometheusRule will be discovered by Prometheus
##
labels: {}
## @param metrics.prometheusRule.rules Prometheus Rule definitions
## - alert: LowInstance
## expr: up{service="{{ template "common.names.fullname" . }}"} < 1
## for: 1m
## labels:
## severity: critical
## annotations:
## description: Service {{ template "common.names.fullname" . }} Apache is down since 1m.
## summary: Apache instance is down.
##
rules: []
## Service Account
## ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/
##
serviceAccount:
## @param serviceAccount.create Enable creation of ServiceAccount for Apache pod
##
create: true
## @param serviceAccount.name The name of the ServiceAccount to use.
## If not set and create is true, a name is generated using the common.names.fullname template
##
name: ""
## @param serviceAccount.automountServiceAccountToken Allows auto mount of ServiceAccountToken on the serviceAccount created
## Can be set to false if pods using this serviceAccount do not need to use K8s API
##
automountServiceAccountToken: false
## @param serviceAccount.annotations Additional custom annotations for the ServiceAccount
##
annotations: {}

View File

@ -0,0 +1,7 @@
services:
web:
build:
context: app
target: builder
ports:
- '8000:8000'

View File

@ -0,0 +1,27 @@
services:
redis:
image: 'redislabs/redismod'
ports:
- '6379:6379'
web1:
restart: on-failure
build: ./web
hostname: web1
ports:
- '81:5000'
web2:
restart: on-failure
build: ./web
hostname: web2
ports:
- '82:5000'
nginx:
build: ./nginx
ports:
- '80:80'
depends_on:
- web1
- web2

View File

@ -0,0 +1,25 @@
services:
prometheus:
image: prom/prometheus
container_name: prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
ports:
- 9090:9090
restart: unless-stopped
volumes:
- ./prometheus:/etc/prometheus
- prom_data:/prometheus
grafana:
image: grafana/grafana
container_name: grafana
ports:
- 3000:3000
restart: unless-stopped
environment:
- GF_SECURITY_ADMIN_USER=admin
- GF_SECURITY_ADMIN_PASSWORD=grafana
volumes:
- ./grafana:/etc/grafana/provisioning/datasources
volumes:
prom_data:

View File

@ -0,0 +1,33 @@
services:
db:
# We use a mariadb image which supports both amd64 & arm64 architecture
image: mariadb:10.6.4-focal
# If you really want to use MySQL, uncomment the following line
#image: mysql:8.0.27
command: '--default-authentication-plugin=mysql_native_password'
volumes:
- db_data:/var/lib/mysql
restart: always
environment:
- MYSQL_ROOT_PASSWORD=somewordpress
- MYSQL_DATABASE=wordpress
- MYSQL_USER=wordpress
- MYSQL_PASSWORD=wordpress
expose:
- 3306
- 33060
wordpress:
image: wordpress:latest
ports:
- 80:80
restart: always
environment:
- WORDPRESS_DB_HOST=db
- WORDPRESS_DB_USER=wordpress
- WORDPRESS_DB_PASSWORD=wordpress
- WORDPRESS_DB_NAME=wordpress
volumes:
db_data:

View File

@ -0,0 +1,42 @@
name: All documents script
# **What it does**: Verifies that the all-documents script works.
# **Why we have it**: Code quality and sustainability.
# **Who does it impact**: docs-engineering
on:
pull_request:
paths:
- 'src/content-render/scripts/all-documents/**'
- 'package*.json'
- .github/workflows/all-documents.yml
permissions:
contents: read
jobs:
all-documents-script:
if: github.repository == 'github/docs-internal'
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: ./.github/actions/node-npm-setup
- name: Run all-documents script
env:
NODE_ENV: production
run: |
echo "Help..."
npm run all-documents -- --help
echo ""
echo "Storing in a file (English only)"
npm run all-documents -- -o all-documents.json -l en
echo ""
echo "Look at the first 50 lines of the file..."
cat all-documents.json | jq | head -n 50
# We're essentially expecting it to not crash and fail.

View File

@ -0,0 +1,45 @@
name: 'Check article-api docs'
# **What it does**: Makes sure changes to the article api are documented.
# **Why we have it**: So what's documented doesn't fall behind
# **Who does it impact**: Docs engineering, CGS team
on:
workflow_dispatch:
pull_request:
paths:
- 'src/article-api/middleware/article.ts'
- 'src/article-api/middleware/pagelist.ts'
# Self-test
- .github/workflows/article-api-docs.yml
permissions:
contents: read
jobs:
check-content-linter-rules-docs:
runs-on: ubuntu-latest
if: github.repository == 'github/docs-internal' || github.repository == 'github/docs'
steps:
- name: Checkout
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: ./.github/actions/node-npm-setup
- name: Check that src/article-api/README.md is up-to-date
run: npm run generate-article-api-docs
- name: Fail if it isn't up-to-date
run: |
if [ -n "$(git status --porcelain)" ]; then
git status
git diff
# Some whitespace for the sake of the message below
echo ""
echo ""
echo "src/article-api/README.md is out of date."
echo "Please run 'npm run generate-article-api-docs' and commit the changes."
exit 1;
fi

View File

@ -0,0 +1,54 @@
name: Auto-add ready-for-doc-review label
# **What it does**: Automatically adds the "ready-for-doc-review" label to DIY docs PRs that contain content or data changes when they are opened in a non-draft state or converted from draft to ready for review.
# **Why we have it**: To ensure DIY docs PRs are automatically added to the docs-content review board without requiring manual labeling.
# **Who does it impact**: Contributors making content changes and docs-content reviewers.
on:
pull_request:
types:
- opened
- ready_for_review
paths:
- 'content/**'
- 'data/**'
permissions:
contents: read
pull-requests: write
jobs:
add-review-label:
name: Add ready-for-doc-review label to DIY docs PRs
if: github.repository == 'github/docs-internal' && github.event.pull_request.draft == false && github.actor != 'github-openapi-bot' && github.actor != 'docs-bot'
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Check team membership
id: membership_check
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
try {
await github.rest.teams.getMembershipForUserInOrg({
org: 'github',
team_slug: 'docs',
username: context.payload.sender.login,
});
return true
} catch(err) {
console.log(err)
return false
}
- name: Add ready-for-doc-review label
if: steps.membership_check.outputs.result == 'false'
env:
GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }}
PR_URL: ${{ github.event.pull_request.html_url }}
run: |
gh pr edit $PR_URL --add-label ready-for-doc-review

View File

@ -0,0 +1,68 @@
name: Auto Close Open Source Dependency Updates
# **What it does**:
# - close-external: Automatically close dependabot's pull requests in the open-source repository.
# **Why we have it**:
# - close-external: To avoid duplicating updates against the internal repository.
# **Who does it impact**: It helps docs engineering focus on higher value work.
on:
pull_request:
paths:
- 'package*.json'
- 'Gemfile*'
- 'Dockerfile'
- '.github/workflows/**'
pull_request_review:
types:
- edited
- submitted
permissions:
contents: write
pull-requests: write
jobs:
close-external:
if: >-
${{
github.repository == 'github/docs' &&
github.event.pull_request.number &&
github.event.pull_request.base.ref == 'main' &&
github.event.pull_request.user.login == 'dependabot[bot]' &&
github.event.pull_request.state == 'open'
}}
runs-on: ubuntu-latest
steps:
- name: Close pull request and delete branch
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_URL: ${{ github.event.pull_request.html_url }}
run: |
gh pr close "$PR_URL" --delete-branch
- name: Comment on the pull request
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_URL: ${{ github.event.pull_request.html_url }}
run: |
gh pr comment "$PR_URL" --body "This dependency update will be handled internally by our engineering team."
# Because we get far too much spam ;_;
- name: Lock conversations
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
env:
PR_NUMBER: ${{ github.event.pull_request.number }}
with:
script: |
try {
await github.rest.issues.lock({
...context.repo,
issue_number: parseInt(process.env.PR_NUMBER, 10),
lock_reason: 'resolved'
})
console.log('Locked the pull request to prevent spam!')
} catch (error) {
console.error(`Failed to lock the pull request. Error: ${error}`)
throw error
}

View File

@ -0,0 +1,170 @@
name: 'Weekly page benchmark'
# **What it does**: Benchmarks all pages via the article API, flags errors and slow pages
# **Why we have it**: Catch perf regressions and broken pages before users hit them
# **Who does it impact**: Docs engineering
on:
workflow_dispatch:
schedule:
- cron: '20 16 * * 1' # Every Monday at 16:20 UTC / 8:20 PST
permissions:
contents: read
jobs:
benchmark:
if: github.repository == 'github/docs-internal'
runs-on: ubuntu-latest
env:
BENCHMARK_LABEL: benchmark-regression
ISSUE_REPO: github/docs-engineering
steps:
- name: Checkout
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: 'false'
- uses: ./.github/actions/node-npm-setup
- name: Build
run: npm run build
- name: Start server
env:
NODE_ENV: production
PORT: 4000
run: |
npm run start-for-ci &
sleep 5
curl --retry-connrefused --retry 6 -I http://localhost:4000/
- name: Run benchmark
run: |
npx tsx src/workflows/benchmark-pages.ts \
--versions "free-pro-team@latest,enterprise-cloud@latest,enterprise-server@latest" \
--modes article-body \
--slow 1000 \
--json /tmp/benchmark-results.json | tee /tmp/benchmark-output.txt
- name: Check results and create issue if needed
if: always()
env:
GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }}
RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
run: |
echo "Reading benchmark results..."
ERRORS=$(jq '.errors | length' /tmp/benchmark-results.json 2>/dev/null || echo "0")
SLOW=$(jq '.slow | length' /tmp/benchmark-results.json 2>/dev/null || echo "0")
TOTAL=$(jq '.totalRequests' /tmp/benchmark-results.json 2>/dev/null || echo "0")
P50=$(jq '.p50' /tmp/benchmark-results.json 2>/dev/null || echo "0")
P99=$(jq '.p99' /tmp/benchmark-results.json 2>/dev/null || echo "0")
MAX=$(jq '.max' /tmp/benchmark-results.json 2>/dev/null || echo "0")
echo "Done reading results: $TOTAL pages, $ERRORS errors, $SLOW slow"
VERSIONS="free-pro-team@latest, enterprise-cloud@latest, enterprise-server@latest"
LANGS="en"
if [ "$ERRORS" = "0" ] && [ "$SLOW" = "0" ]; then
echo "✅ All clear — $TOTAL pages, p50=${P50}ms, p99=${P99}ms, max=${MAX}ms"
echo "Checking for existing open issue..."
existing=$(gh issue list \
--repo "$ISSUE_REPO" \
--label "$BENCHMARK_LABEL" \
--state open \
--json number \
--jq '.[0].number // empty' 2>/dev/null || true)
if [ -n "$existing" ]; then
echo "Closing issue #$existing..."
gh issue close "$existing" \
--repo "$ISSUE_REPO" \
--comment "All clear as of $RUN_URL — closing."
echo "Done closing issue #$existing"
else
echo "No existing issue to close"
fi
exit 0
fi
PROBLEM_COUNT=$((ERRORS + SLOW))
echo "Found $ERRORS errors and $SLOW slow pages ($PROBLEM_COUNT total problems)"
echo "Ensuring label exists..."
gh label create "$BENCHMARK_LABEL" \
--repo "$ISSUE_REPO" \
--description "Weekly page benchmark found slow or errored pages" \
--color "e16f24" 2>/dev/null || true
echo "Done ensuring label"
echo "Building issue body..."
BODY_FILE=/tmp/benchmark-issue-body.md
{
echo "## Weekly page benchmark found issues"
echo ""
echo "**Run:** $RUN_URL"
echo "**Languages:** $LANGS"
echo "**Versions:** $VERSIONS"
echo "**Total pages:** $TOTAL"
echo "**Stats:** p50=${P50}ms · p99=${P99}ms · max=${MAX}ms"
echo "**Errors:** $ERRORS"
echo "**Slow (≥1000ms):** $SLOW"
} > "$BODY_FILE"
if [ "$ERRORS" -gt 0 ]; then
{
echo ""
echo "### Errors"
echo ""
echo "| Status | Mode | Path | Error |"
echo "|--------|------|------|-------|"
jq -r '.errors[] | "| \(.status) | \(.mode) | \(.path) | \(.errorBody // "" | gsub("\\|"; "\\|") | gsub("\r"; " ") | gsub("\n"; " ")) |"' /tmp/benchmark-results.json
} >> "$BODY_FILE"
fi
if [ "$SLOW" -gt 0 ]; then
{
echo ""
echo "### Slow pages"
echo ""
echo "| Time | Mode | Path |"
echo "|------|------|------|"
jq -r '.slow[] | "| \(.timeMs)ms | \(.mode) | \(.path) |"' /tmp/benchmark-results.json
} >> "$BODY_FILE"
fi
echo "Done building issue body"
echo "Checking for existing open issue..."
existing=$(gh issue list \
--repo "$ISSUE_REPO" \
--label "$BENCHMARK_LABEL" \
--state open \
--json number \
--jq '.[0].number // empty' 2>/dev/null || true)
if [ -n "$existing" ]; then
echo "Commenting on existing issue #$existing..."
gh issue comment "$existing" \
--repo "$ISSUE_REPO" \
--body-file "$BODY_FILE"
echo "Done commenting on issue #$existing"
else
echo "Creating new issue..."
gh issue create \
--repo "$ISSUE_REPO" \
--label "$BENCHMARK_LABEL" \
--title "[Benchmark] ${PROBLEM_COUNT} slow or errored pages detected" \
--body-file "$BODY_FILE"
echo "Done creating issue"
fi
- uses: ./.github/actions/slack-alert
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
with:
slack_channel_id: ${{ secrets.DOCS_ALERTS_SLACK_CHANNEL_ID }}
slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}
- uses: ./.github/actions/create-workflow-failure-issue
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
with:
token: ${{ secrets.DOCS_BOT_PAT_BASE }}

View File

@ -0,0 +1,762 @@
name: Changelog agent — draft entry when a qualified PR merges
# **What it does**: When a PR merges that closes a docs-content issue with a
# parent issue, uses an LLM to draft a changelog entry, opens a PR in
# github/docs-content, and DMs the author in Slack for review.
# **Why we have it**: Automates the changelog drafting process so authors
# don't have to remember to write a changelog entry manually.
# **Who does it impact**: docs-content team members.
on:
pull_request:
types: [closed]
workflow_dispatch:
inputs:
pr_number:
description: 'PR number to test with (must be a merged PR)'
required: true
type: number
dry_run:
description: 'Dry run — log actions but do not create PR or send Slack DM'
required: false
type: boolean
default: true
concurrency:
group: changelog-agent-${{ github.event.pull_request.number || github.event.inputs.pr_number }}
cancel-in-progress: true
permissions:
contents: read
pull-requests: write
issues: write
env:
CHANGELOG_FILE: docs-content-docs/docs-content-workflows/changelog-internal.md
TARGET_REPO: github/docs-content
jobs:
generate-changelog:
if: >-
github.repository == 'github/docs-internal' &&
(
(github.event_name == 'pull_request' && github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'main') ||
github.event_name == 'workflow_dispatch'
)
runs-on: ubuntu-latest
steps:
- name: Resolve PR data
id: resolve_pr
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
let pr;
if (context.eventName === 'workflow_dispatch') {
const prNumber = parseInt('${{ inputs.pr_number }}', 10);
const { data } = await github.rest.pulls.get({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
});
pr = data;
if (!pr.merged) {
core.setFailed(`PR #${prNumber} has not been merged. Cannot test.`);
return;
}
} else {
pr = context.payload.pull_request;
}
core.setOutput('pr_number', pr.number.toString());
core.setOutput('pr_author', pr.user.login);
core.setOutput('pr_title', pr.title);
core.setOutput('pr_body', pr.body || '');
core.setOutput('pr_url', pr.html_url);
- name: Check if PR author is in the team
id: check_team
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
const author = '${{ steps.resolve_pr.outputs.pr_author }}';
// Fetch github-to-slack.json from docs-content via API
let mapping = {};
try {
const { data } = await github.rest.repos.getContent({
owner: 'github',
repo: 'docs-content',
path: '.github/github-to-slack.json',
});
const content = Buffer.from(data.content, 'base64').toString('utf-8');
mapping = JSON.parse(content);
} catch (err) {
core.setFailed(`Could not fetch github-to-slack.json from docs-content: ${err.message}`);
return;
}
// Remove non-user keys (like _comment)
const teamMembers = Object.keys(mapping).filter(k => !k.startsWith('_'));
if (!teamMembers.includes(author)) {
core.info(`PR author @${author} is not in the team mapping. Skipping.`);
core.setOutput('is_team_member', 'false');
return;
}
core.info(`PR author @${author} is a team member. Proceeding.`);
core.setOutput('is_team_member', 'true');
- name: Extract linked docs-content issue
if: steps.check_team.outputs.is_team_member == 'true'
id: extract_issue
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
PR_BODY: ${{ steps.resolve_pr.outputs.pr_body }}
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
const body = process.env.PR_BODY || '';
// Match closing keywords followed by docs-content issue references.
// Supports: closes github/docs-content#123, fixes https://github.com/github/docs-content/issues/123
const patterns = [
/(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?):?\s+github\/docs-content#(\d+)/gi,
/(?:close[sd]?|fix(?:e[sd])?|resolve[sd]?):?\s+https:\/\/github\.com\/github\/docs-content\/issues\/(\d+)/gi,
];
let issueNumber = null;
for (const pattern of patterns) {
const match = pattern.exec(body);
if (match) {
issueNumber = parseInt(match[1], 10);
break;
}
}
if (!issueNumber) {
core.info('No linked docs-content issue found in PR body. Exiting.');
core.setOutput('found', 'false');
return;
}
core.info(`Found linked docs-content issue: #${issueNumber}`);
core.setOutput('found', 'true');
core.setOutput('issue_number', issueNumber.toString());
- name: Check for parent issue
if: steps.extract_issue.outputs.found == 'true'
id: check_parent
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
const issueNumber = parseInt('${{ steps.extract_issue.outputs.issue_number }}', 10);
let issue;
try {
const { data } = await github.rest.issues.get({
owner: 'github',
repo: 'docs-content',
issue_number: issueNumber,
});
issue = data;
} catch (err) {
core.info(`Could not fetch docs-content issue #${issueNumber}: ${err.message}. Skipping.`);
core.setOutput('has_parent', 'false');
return;
}
// Query for parent issue via GraphQL
const query = `
query($nodeId: ID!) {
node(id: $nodeId) {
... on Issue {
parent {
number
title
body
url
author { login }
assignees(first: 10) {
nodes { login }
}
repository {
nameWithOwner
}
}
}
}
}
`;
let result;
try {
result = await github.graphql(query, { nodeId: issue.node_id });
} catch (err) {
core.info(`GraphQL parent query failed: ${err.message}. Skipping.`);
core.setOutput('has_parent', 'false');
return;
}
const parent = result.node?.parent;
if (!parent) {
core.info('docs-content issue has no parent issue. Exiting.');
core.setOutput('has_parent', 'false');
return;
}
core.info(`Found parent issue: ${parent.repository.nameWithOwner}#${parent.number}`);
core.setOutput('has_parent', 'true');
core.setOutput('parent_number', parent.number.toString());
core.setOutput('parent_title', parent.title);
core.setOutput('parent_body', parent.body || '');
core.setOutput('parent_url', parent.url);
core.setOutput('parent_author', parent.author?.login || '');
core.setOutput('parent_assignees', (parent.assignees?.nodes || []).map(a => a.login).join(','));
core.setOutput('parent_repo', parent.repository.nameWithOwner);
// Also store the docs-content issue details
core.setOutput('dc_issue_title', issue.title);
core.setOutput('dc_issue_body', issue.body || '');
- name: Gather PR context
if: steps.check_parent.outputs.has_parent == 'true'
id: gather_context
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
PR_TITLE: ${{ steps.resolve_pr.outputs.pr_title }}
PR_BODY: ${{ steps.resolve_pr.outputs.pr_body }}
PR_URL: ${{ steps.resolve_pr.outputs.pr_url }}
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
const prNumber = parseInt('${{ steps.resolve_pr.outputs.pr_number }}', 10);
const prAuthor = '${{ steps.resolve_pr.outputs.pr_author }}';
// Get approved reviewers (exclude bots and PR author)
const { data: reviews } = await github.rest.pulls.listReviews({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
});
const approvedReviewers = [...new Set(
reviews
.filter(r => r.state === 'APPROVED' && r.user.type !== 'Bot' && r.user.login !== prAuthor)
.map(r => r.user.login)
)];
// Get changed files (paths only, limit to 50)
const { data: files } = await github.rest.pulls.listFiles({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: prNumber,
per_page: 50,
});
const changedFiles = files.map(f => f.filename);
core.setOutput('pr_author', prAuthor);
core.setOutput('pr_title', process.env.PR_TITLE || '');
core.setOutput('pr_body', process.env.PR_BODY || '');
core.setOutput('pr_url', process.env.PR_URL || '');
core.setOutput('pr_number', prNumber.toString());
core.setOutput('approved_reviewers', approvedReviewers.join(','));
core.setOutput('changed_files', changedFiles.join('\n'));
- name: Check for existing changelog PR
if: steps.check_parent.outputs.has_parent == 'true'
id: check_existing
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
const branchName = `changelog-agent-${{ steps.resolve_pr.outputs.pr_number }}`;
const { data: pulls } = await github.rest.pulls.list({
owner: 'github',
repo: 'docs-content',
head: `github:${branchName}`,
state: 'open',
});
if (pulls.length > 0) {
core.info(`Changelog PR already exists: ${pulls[0].html_url}`);
core.setOutput('exists', 'true');
core.setOutput('existing_pr_url', pulls[0].html_url);
} else {
core.setOutput('exists', 'false');
}
- name: Read existing changelog examples
if: steps.check_parent.outputs.has_parent == 'true' && steps.check_existing.outputs.exists == 'false'
id: read_examples
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
// Fetch changelog-internal.md from docs-content
const { data } = await github.rest.repos.getContent({
owner: 'github',
repo: 'docs-content',
path: 'docs-content-docs/docs-content-workflows/changelog-internal.md',
});
const changelog = Buffer.from(data.content, 'base64').toString('utf-8');
// Extract the first 3 entries (each starts with **date**)
const lines = changelog.split('\n');
let count = 0;
let examples = [];
let capturing = false;
for (const line of lines) {
if (/^\*\*\d/.test(line)) {
count++;
if (count > 3) break;
capturing = true;
}
if (capturing) examples.push(line);
}
core.setOutput('examples', examples.join('\n'));
- name: Set up Node.js
if: steps.check_parent.outputs.has_parent == 'true' && steps.check_existing.outputs.exists == 'false'
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version-file: 'package.json'
- name: Prepare prompts for LLM
if: steps.check_parent.outputs.has_parent == 'true' && steps.check_existing.outputs.exists == 'false'
id: prepare_prompts
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
PR_TITLE: ${{ steps.gather_context.outputs.pr_title }}
PR_BODY: ${{ steps.gather_context.outputs.pr_body }}
PR_AUTHOR: ${{ steps.gather_context.outputs.pr_author }}
CHANGED_FILES: ${{ steps.gather_context.outputs.changed_files }}
APPROVED_REVIEWERS: ${{ steps.gather_context.outputs.approved_reviewers }}
DC_ISSUE_TITLE: ${{ steps.check_parent.outputs.dc_issue_title }}
DC_ISSUE_BODY: ${{ steps.check_parent.outputs.dc_issue_body }}
PARENT_TITLE: ${{ steps.check_parent.outputs.parent_title }}
PARENT_BODY: ${{ steps.check_parent.outputs.parent_body }}
PARENT_AUTHOR: ${{ steps.check_parent.outputs.parent_author }}
PARENT_ASSIGNEES: ${{ steps.check_parent.outputs.parent_assignees }}
CHANGELOG_EXAMPLES: ${{ steps.read_examples.outputs.examples }}
with:
script: |
const fs = require('fs');
const today = new Date();
const dateStr = today.toLocaleDateString('en-GB', {
day: 'numeric', month: 'long', year: 'numeric'
});
const systemPrompt = `You are a technical writer for GitHub Docs. You write changelog entries for the internal docs changelog.
Rules:
- Write in plain, clear language suitable for an internal audience of docs team members
- Focus on what shipped and its impact on users of docs.github.com
- Use present tense or past tense consistently
- Include links to relevant docs pages when possible (use full https://docs.github.com/... URLs)
- The entry MUST include these sections in order:
1. A brief description paragraph of what shipped
2. **Anticipated impact**: One or two sentences about who is affected and how
3. **Authored by**: @username of the PR author
4. **Thanks to**: @usernames of reviewers and stakeholders who helped
- Do NOT include any internal issue numbers, PR numbers, or repo references in the description
- Do NOT disclose sensitive information
- Match the tone and structure of the example entries provided
- Output ONLY the changelog entry text (no date header, no <hr> tag — those are added automatically)`;
const reviewers = process.env.APPROVED_REVIEWERS
? process.env.APPROVED_REVIEWERS.split(',').filter(r => r !== process.env.PR_AUTHOR).map(r => `@${r}`).join(', ')
: '';
const stakeholders = [
process.env.PARENT_AUTHOR,
...(process.env.PARENT_ASSIGNEES ? process.env.PARENT_ASSIGNEES.split(',') : []),
].filter(Boolean).filter(u => u !== process.env.PR_AUTHOR).filter((v, i, a) => a.indexOf(v) === i).map(u => `@${u}`).join(', ');
const thanksTo = [reviewers, stakeholders].filter(Boolean).join(', ');
const userPrompt = `Draft a changelog entry for a docs change that just shipped.
## PR details
Title: ${process.env.PR_TITLE}
Description: ${process.env.PR_BODY}
Author: @${process.env.PR_AUTHOR}
Changed files:
${process.env.CHANGED_FILES}
## docs-content issue
Title: ${process.env.DC_ISSUE_TITLE}
Description: ${process.env.DC_ISSUE_BODY}
## Parent issue (broader feature/initiative)
Title: ${process.env.PARENT_TITLE}
Description: ${process.env.PARENT_BODY}
## Credits
Author: @${process.env.PR_AUTHOR}
Thanks to: ${thanksTo || 'N/A'}
## Example entries from the existing changelog (match this style):
${process.env.CHANGELOG_EXAMPLES}
Write the changelog entry now. Include the **Anticipated impact**, **Authored by**, and **Thanks to** sections.`;
fs.writeFileSync('system-prompt.txt', systemPrompt);
fs.writeFileSync('prompt.txt', userPrompt);
core.setOutput('date_str', dateStr);
- name: Generate changelog draft via Copilot
if: steps.check_parent.outputs.has_parent == 'true' && steps.check_existing.outputs.exists == 'false'
id: generate_draft
uses: actions/ai-inference@17ff458cb182449bbb2e43701fcd98f6af8f6570 # v2.1.0
with:
provider: copilot
model: gpt-4.1
prompt-file: prompt.txt
system-prompt-file: system-prompt.txt
max-completion-tokens: 1000
temperature: 0.3
env:
COPILOT_GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_COPILOT }}
- name: Dry run summary
if: steps.generate_draft.outputs.response != '' && inputs.dry_run == true
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
PR_AUTHOR: ${{ steps.gather_context.outputs.pr_author }}
PR_URL: ${{ steps.gather_context.outputs.pr_url }}
PARENT_TITLE: ${{ steps.check_parent.outputs.parent_title }}
DRAFT: ${{ steps.generate_draft.outputs.response }}
with:
script: |
core.info('=== DRY RUN — no PR will be created, no Slack DM sent ===');
core.info(`PR author: ${process.env.PR_AUTHOR || ''}`);
core.info(`Source PR: ${process.env.PR_URL || ''}`);
core.info(`Parent issue: ${process.env.PARENT_TITLE || ''}`);
core.info('--- Generated changelog draft ---');
core.info((process.env.DRAFT || '').replace(/^::/gm, ': :'));
core.info('--- End of draft ---');
- name: Create changelog PR in docs-content
if: steps.generate_draft.outputs.response != '' && steps.check_existing.outputs.exists == 'false' && inputs.dry_run != true
id: create_pr
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
DRAFT: ${{ steps.generate_draft.outputs.response }}
DATE_STR: ${{ steps.prepare_prompts.outputs.date_str }}
PR_AUTHOR: ${{ steps.gather_context.outputs.pr_author }}
PR_URL: ${{ steps.gather_context.outputs.pr_url }}
PR_NUMBER: ${{ steps.gather_context.outputs.pr_number }}
APPROVED_REVIEWERS: ${{ steps.gather_context.outputs.approved_reviewers }}
PARENT_TITLE: ${{ steps.check_parent.outputs.parent_title }}
PARENT_URL: ${{ steps.check_parent.outputs.parent_url }}
PARENT_AUTHOR: ${{ steps.check_parent.outputs.parent_author }}
PARENT_ASSIGNEES: ${{ steps.check_parent.outputs.parent_assignees }}
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
const branchName = `changelog-agent-${{ steps.resolve_pr.outputs.pr_number }}`;
const filePath = 'docs-content-docs/docs-content-workflows/changelog-internal.md';
// Get the current changelog file from docs-content
const { data: fileData } = await github.rest.repos.getContent({
owner: 'github',
repo: 'docs-content',
path: filePath,
});
let changelog = Buffer.from(fileData.content, 'base64').toString('utf-8');
// Build the new entry
const entry = `**${process.env.DATE_STR}**\n\n${process.env.DRAFT}\n\n<hr>`;
// Insert after the first H1 heading so leading frontmatter, comments,
// or blank lines do not affect placement.
const lines = changelog.split('\n');
const headingIndex = lines.findIndex((line) => line.startsWith('# '));
if (headingIndex === -1) {
changelog = `${entry}\n${changelog}`;
} else {
const beforeAndHeading = lines.slice(0, headingIndex + 1).join('\n');
const rest = lines.slice(headingIndex + 1).join('\n');
changelog = rest
? `${beforeAndHeading}\n\n${entry}\n${rest}`
: `${beforeAndHeading}\n\n${entry}`;
}
// Get the default branch SHA for creating a new branch
const { data: ref } = await github.rest.git.getRef({
owner: 'github',
repo: 'docs-content',
ref: 'heads/main',
});
// Create the branch in docs-content
try {
await github.rest.git.createRef({
owner: 'github',
repo: 'docs-content',
ref: `refs/heads/${branchName}`,
sha: ref.object.sha,
});
} catch (err) {
if (err.status === 422) {
core.info('Branch already exists, will update file on existing branch.');
} else {
throw err;
}
}
// Fetch the file from the branch (handles both new and existing branches)
const { data: branchFileData } = await github.rest.repos.getContent({
owner: 'github',
repo: 'docs-content',
path: filePath,
ref: branchName,
});
// Update the changelog file on the new branch
await github.rest.repos.createOrUpdateFileContents({
owner: 'github',
repo: 'docs-content',
path: filePath,
message: `Changelog draft for docs-internal PR #${process.env.PR_NUMBER}`,
content: Buffer.from(changelog).toString('base64'),
sha: branchFileData.sha,
branch: branchName,
committer: {
name: 'github-actions[bot]',
email: 'github-actions[bot]@users.noreply.github.com',
},
});
// Build credits for the PR body
const reviewers = process.env.APPROVED_REVIEWERS
? process.env.APPROVED_REVIEWERS.split(',').map(r => `@${r}`).join(', ')
: 'None';
const parentAuthor = process.env.PARENT_AUTHOR ? `@${process.env.PARENT_AUTHOR}` : 'Unknown';
const parentAssignees = process.env.PARENT_ASSIGNEES
? process.env.PARENT_ASSIGNEES.split(',').map(a => `@${a}`).join(', ')
: 'None';
const prBody = [
'### Automated docs changelog draft',
'',
`_Generated by the changelog-agent workflow from [docs-internal PR #${process.env.PR_NUMBER}](${process.env.PR_URL})._`,
'',
'**⚠️ This is an AI-generated draft. Please review carefully before merging.**',
'',
`**Source PR:** [docs-internal#${process.env.PR_NUMBER}](${process.env.PR_URL})`,
`**Parent initiative:** [${process.env.PARENT_TITLE}](${process.env.PARENT_URL})`,
'',
'#### Credits',
`- **Author:** @${process.env.PR_AUTHOR}`,
`- **Reviewers:** ${reviewers}`,
`- **Parent issue author:** ${parentAuthor}`,
`- **Parent issue assignees:** ${parentAssignees}`,
'',
'#### Review checklist',
'- [ ] Entry is accurate and covers what shipped',
'- [ ] Content is appropriate for the internal audience',
'- [ ] Format is consistent with other changelog entries',
'- [ ] No sensitive information disclosed',
].join('\n');
const { data: pullRequest } = await github.rest.pulls.create({
owner: 'github',
repo: 'docs-content',
title: `Changelog draft for docs-internal PR #${process.env.PR_NUMBER}`,
body: prBody,
head: branchName,
base: 'main',
draft: true,
});
// Add labels
try {
await github.rest.issues.addLabels({
owner: 'github',
repo: 'docs-content',
issue_number: pullRequest.number,
labels: ['ready-for-doc-review', 'skip FR board', 'llm-generated'],
});
} catch (err) {
core.warning(`Failed to add labels: ${err.message}`);
}
// Assign to PR author
try {
await github.rest.issues.addAssignees({
owner: 'github',
repo: 'docs-content',
issue_number: pullRequest.number,
assignees: [process.env.PR_AUTHOR],
});
} catch (err) {
core.warning(`Failed to assign PR to @${process.env.PR_AUTHOR}: ${err.message}`);
}
core.setOutput('changelog_pr_url', pullRequest.html_url);
core.setOutput('changelog_pr_number', pullRequest.number.toString());
- name: Notify author via Slack DM
if: steps.create_pr.outputs.changelog_pr_url != '' && inputs.dry_run != true
id: slack_notify
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
env:
SLACK_TOKEN: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}
PR_AUTHOR: ${{ steps.gather_context.outputs.pr_author }}
CHANGELOG_PR_URL: ${{ steps.create_pr.outputs.changelog_pr_url }}
PR_URL: ${{ steps.gather_context.outputs.pr_url }}
APPROVED_REVIEWERS: ${{ steps.gather_context.outputs.approved_reviewers }}
PARENT_TITLE: ${{ steps.check_parent.outputs.parent_title }}
PARENT_AUTHOR: ${{ steps.check_parent.outputs.parent_author }}
PARENT_ASSIGNEES: ${{ steps.check_parent.outputs.parent_assignees }}
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
const author = process.env.PR_AUTHOR;
const changelogPrUrl = process.env.CHANGELOG_PR_URL;
// Fetch GitHub-to-Slack mapping from docs-content
let slackMapping = {};
try {
const { data } = await github.rest.repos.getContent({
owner: 'github',
repo: 'docs-content',
path: '.github/github-to-slack.json',
});
const content = Buffer.from(data.content, 'base64').toString('utf-8');
slackMapping = JSON.parse(content);
} catch (err) {
core.warning(`Could not fetch github-to-slack.json: ${err.message}`);
}
const slackUserId = slackMapping[author];
// Build credits summary for the DM
const reviewers = process.env.APPROVED_REVIEWERS
? process.env.APPROVED_REVIEWERS.split(',').join(', ')
: 'none';
const stakeholders = [
process.env.PARENT_AUTHOR,
...(process.env.PARENT_ASSIGNEES ? process.env.PARENT_ASSIGNEES.split(',') : []),
].filter(Boolean).filter((v, i, a) => a.indexOf(v) === i).join(', ');
const slackMessage = [
`👋 Hi! A changelog draft has been created for your merged PR:`,
``,
`📝 *Changelog PR:* ${changelogPrUrl}`,
`🔗 *Source PR:* ${process.env.PR_URL}`,
`🎯 *Parent initiative:* ${process.env.PARENT_TITLE}`,
``,
`*Reviewers to thank:* ${reviewers || 'none'}`,
`*Stakeholders to thank:* ${stakeholders || 'none'}`,
``,
`Please review the draft changelog entry and merge or close the PR. The entry is AI-generated, so double-check accuracy and tone.`,
].join('\n');
if (slackUserId) {
try {
const response = await fetch('https://slack.com/api/chat.postMessage', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SLACK_TOKEN}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
channel: slackUserId,
text: slackMessage,
}),
});
const result = await response.json();
if (result.ok) {
core.info(`Slack DM sent to ${author} (${slackUserId})`);
core.setOutput('notified_via', 'slack');
return;
} else {
core.warning(`Slack API error: ${result.error}`);
}
} catch (err) {
core.warning(`Slack DM failed: ${err.message}`);
}
} else {
core.warning(`No Slack mapping found for GitHub user: ${author}`);
}
// Fallback: post a GitHub comment on the source PR
core.info('Falling back to GitHub comment notification.');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: parseInt('${{ steps.resolve_pr.outputs.pr_number }}', 10),
body: [
`👋 @${author} — A changelog draft has been created for this PR!`,
``,
`📝 **Changelog PR:** ${changelogPrUrl}`,
``,
`Please review the draft entry and merge or close it. The entry is AI-generated, so double-check accuracy and tone.`,
``,
`**Reviewers to thank:** ${reviewers || 'none'}`,
`**Stakeholders to thank:** ${stakeholders || 'none'}`,
].join('\n'),
});
core.setOutput('notified_via', 'github_comment');
- name: Post agent marker comment
if: steps.create_pr.outputs.changelog_pr_url != '' && inputs.dry_run != true
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
const changelogPrUrl = '${{ steps.create_pr.outputs.changelog_pr_url }}';
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: parseInt('${{ steps.resolve_pr.outputs.pr_number }}', 10),
body: `<!-- changelog-agent-handled -->\n🤖 A changelog draft PR has been automatically created in docs-content: ${changelogPrUrl}`,
});
- name: Send Slack failure alert
if: failure()
env:
SLACK_CHANNEL_ID: ${{ secrets.DOCS_ALERTS_SLACK_CHANNEL_ID }}
SLACK_TOKEN: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}
WORKFLOW_NAME: ${{ github.workflow }}
REPOSITORY: ${{ github.repository }}
RUN_ID: ${{ github.run_id }}
SERVER_URL: ${{ github.server_url }}
run: |
curl -sS -X POST https://slack.com/api/chat.postMessage \
-H "Authorization: Bearer ${SLACK_TOKEN}" \
-H "Content-Type: application/json; charset=utf-8" \
--data "$(cat <<EOF
{
"channel": "${SLACK_CHANNEL_ID}",
"text": ":warning: Workflow failure in ${REPOSITORY}",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": ":warning: *${WORKFLOW_NAME}* failed in *${REPOSITORY}*"
}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "<${SERVER_URL}/${REPOSITORY}/actions/runs/${RUN_ID}|View workflow run>"
}
}
]
}
EOF
)"

View File

@ -0,0 +1,66 @@
name: Changelog prompt when a PR is closed
on:
pull_request:
types: [closed]
permissions:
contents: read
pull-requests: write
jobs:
comment-on-pr:
# This workflow should only run on the 'github/docs-internal' repository because it posts changelog instructions
# and links that are specific to the internal documentation process and resources.
# It also only runs if PR is merged into the main branch.
if: github.repository == 'github/docs-internal' && github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'main'
runs-on: ubuntu-latest
steps:
- name: Check if PR author is in docs-content team
id: check_team
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
try {
const pr = context.payload.pull_request;
await github.rest.teams.getMembershipForUserInOrg({
org: 'github',
team_slug: 'docs-content',
username: pr.user.login,
});
core.exportVariable('CONTINUE_WORKFLOW', 'true');
} catch(err) {
core.info("Workflow triggered by a merged PR, but the PR author is not a member of the docs-content team.");
core.exportVariable('CONTINUE_WORKFLOW', 'false');
}
- name: Post changelog instructions comment
if: env.CONTINUE_WORKFLOW == 'true'
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
// Get PR author username
const pr = context.payload.pull_request;
const prAuthor = pr.user.login;
// Compose the comment body with readable YAML and correct formatting
const commentBody =
"👋 @" + prAuthor +
" - Did this PR add noteworthy changes to the GitHub docs? If so, you might want to publicize this by adding an entry to " +
"the [Docs changelog](https://github.com/github/docs-internal/blob/main/CHANGELOG.md).\n\n" +
"To do this, type `/changelog` in a new comment on this PR and complete the fields.\n\n" +
"A message will be posted to the **#docs-changelog** channel and a PR will be raised to update the [CHANGELOG.md](https://github.com/github/docs-internal/blob/main/CHANGELOG.md) file.";
// Post the comment
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
body: commentBody
});

View File

@ -0,0 +1,82 @@
name: Check for Spammy Issues
# **What it does**: This action closes low value pull requests in the open-source repository.
# **Why we have it**: We get lots of spam in the open-source repository.
# **Who does it impact**: Open-source contributors.
on:
issues:
types: [opened]
permissions:
contents: read
jobs:
spammy-title-check:
name: Remove issues with spammy titles
if: github.repository == 'github/docs'
runs-on: ubuntu-latest
steps:
- uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
const issue = context.payload.issue
const owner = 'github'
const repo = 'docs'
const titleWordCount = issue.title.trim().split(' ').length
const titleWordCountMin = 3
try {
await github.rest.teams.getMembershipForUserInOrg({
org: 'github',
team_slug: 'employees',
username: context.payload.sender.login,
});
// Do not perform this workflow with GitHub employees. This return
// statement only gets hit if the user is a GitHub employee
return
} catch (err) {
// An error will be thrown if the user is not a GitHub employee
// If a user is not a GitHub employee, we should check to see if title has at least the minimum required number of words in it and if it does, we can exit the workflow
if (titleWordCount >= titleWordCountMin) {
return
}
}
//
// Assuming the user is not a GitHub employee and the issue title
// does not contain the minimum number of words required, proceed.
//
// Close the issue and add the invalid label
await github.rest.issues.update({
owner: owner,
repo: repo,
issue_number: issue.number,
labels: ['invalid'],
state: 'closed'
});
// Comment on the issue
await github.rest.issues.createComment({
owner: owner,
repo: repo,
issue_number: issue.number,
body: `This issue may have been opened accidentally. I'm going to close it now, but feel free to open a new issue with a more descriptive title!`
});
// Add the issue to the Done column on the triage board
try {
await github.rest.projects.createCard({
column_id: 11167427,
content_id: context.payload.issue.id,
content_type: "Issue"
});
} catch (error) {
console.log(error);
}

View File

@ -0,0 +1,63 @@
name: Close bad repo-sync PRs
# **What it does**:
# Closes and PR from `repo-sync` to `main` that wasn't created by a Hubber.
# **Why we have it**:
# Unfortunately, a lot of PRs in github/docs are created by people who
# shouldn't be creating such PRs. We bot our bots to own it.
# **Who does it impact**: Open-source.
on:
# Necessary in lieu of `pull_request` so that PRs opened from forks can be closed if they try to push to a repo sync branch.
pull_request_target:
permissions:
contents: write
pull-requests: write
jobs:
close-invalid-repo-sync-pr:
if: ${{ github.repository == 'github/docs' && github.event.pull_request.base.ref == 'main' && github.event.pull_request.head.ref == 'repo-sync' }}
name: Close if invalid repo-sync PR author
runs-on: ubuntu-latest
steps:
- name: Close pull request if unwanted
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
const { owner, repo } = context.repo
const prCreator = context.actor
const prNumber = context.issue.number
try {
await github.rest.teams.getMembershipForUserInOrg({
org: 'github',
team_slug: 'employees',
username: prCreator
})
// If the PR creator is a GitHub employee, stop now
console.log("PR creator is a GitHub employee")
return
} catch (err) {
// An error will be thrown if the user is not a GitHub employee.
// That said, we still want to proceed anyway!
}
// Close the PR and add the invalid label
await github.rest.issues.update({
owner,
repo,
issue_number: prNumber,
labels: ['invalid'],
state: 'closed'
})
// Comment on the PR
await github.rest.issues.createComment({
owner,
repo,
issue_number: prNumber,
body: "Please leave this `repo-sync` branch to the robots!\n\nI'm going to close this pull request now, but feel free to open a new issue in the repository!"
})

View File

@ -0,0 +1,48 @@
name: Close issue/PR on adding invalid label
# **What it does**: This action closes invalid pull requests in the open-source repository.
# **Why we have it**: We get lots of spam in the open-source repository.
# **Who does it impact**: Open-source contributors.
on:
issues:
types: [labeled]
# Needed in lieu of `pull_request` so that PRs from a fork can be
# closed when marked as invalid.
pull_request_target:
types: [labeled]
permissions:
contents: read
issues: write
pull-requests: write
jobs:
close-on-adding-invalid-label:
if: github.repository == 'github/docs' && github.event.label.name == 'invalid'
runs-on: ubuntu-latest
steps:
- name: Close issue
if: ${{ github.event_name == 'issues' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
ISSUE_URL: ${{ github.event.issue.html_url }}
run: gh issue close "$ISSUE_URL"
- name: Close PR
if: ${{ github.event_name == 'pull_request_target' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PR_URL: ${{ github.event.pull_request.html_url }}
run: gh pr close "$PR_URL"
- name: Check out repo
if: ${{ failure() && github.event_name != 'pull_request_target' }}
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: ./.github/actions/slack-alert
if: ${{ failure() && github.event_name != 'pull_request_target' }}
with:
slack_channel_id: ${{ secrets.DOCS_ALERTS_SLACK_CHANNEL_ID }}
slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}

View File

@ -0,0 +1,48 @@
name: CodeQL analysis
# **What it does**: This runs CodeQL on our repository.
# **Why we have it**: Security scanning.
# **Who does it impact**: Docs engineering.
on:
pull_request:
branches:
- main
# This is so that when CodeQL runs on a pull request, it can compare
# against the state of the base branch.
push:
branches:
- main
permissions:
actions: read
contents: read
security-events: write
# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
cancel-in-progress: true
jobs:
build:
if: github.repository == 'github/docs-internal' || github.repository == 'github/docs'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: github/codeql-action/init@e296a935590eb16afc0c0108289f68c87e2a89a5 # v4.30.7
with:
languages: javascript # comma separated list of values from {go, python, javascript, java, cpp, csharp, ruby}
- uses: github/codeql-action/analyze@e296a935590eb16afc0c0108289f68c87e2a89a5 # v4.30.7
continue-on-error: true
- uses: ./.github/actions/slack-alert
if: ${{ failure() && github.event_name != 'pull_request' }}
with:
slack_channel_id: ${{ secrets.DOCS_ALERTS_SLACK_CHANNEL_ID }}
slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}
- uses: ./.github/actions/create-workflow-failure-issue
if: ${{ failure() && github.event_name != 'pull_request' }}
with:
token: ${{ secrets.DOCS_BOT_PAT_BASE }}

View File

@ -0,0 +1,33 @@
# This workflow provides information when a contributor edits a release note file
name: Comment on release note changes
on:
pull_request:
types:
- opened
paths:
- data/release-notes/enterprise-server/**
- .github/workflows/comment-release-note-info.yml
permissions:
contents: read
pull-requests: write
jobs:
comment:
# Do not add this comment on PRs created by the bot during the standard patch release process
# or in the github/docs repository
if: github.event.pull_request.user.login != 'release-controller[bot]' && github.repository == 'github/docs-internal'
runs-on: ubuntu-latest
steps:
- uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9
with:
issue-number: ${{ github.event.pull_request.number }}
body: |
Thank you for updating our GitHub Enterprise Server release notes. Please request a technical review for your changes. Once the technical review is complete, a member of the `docs-content-enterprise` team will review your changes.
- If the change is urgent, post in `#docs-content-enterprise` on Slack.
- Review the [style guide for release notes](https://docs.github.com/en/contributing/style-guide-and-content-model/style-guide#release-notes).
- If you're updating or adding a note, add a datestamp in the format `[Updated: YYYY-MM-DD]`.
- If you're removing a note, add an [Errata](https://docs.github.com/en/contributing/style-guide-and-content-model/style-guide#errata) section with details of the change.

View File

@ -0,0 +1,91 @@
name: Confirm internal staff meant to post in public
# **What it does**: If a GitHub staff makes an issue/pull request in the open-source repo, creates an issue in the internal one to verify intent.
# **Why we have it**: We don't want GitHub staff accidentally making issues/pull requests in the wrong repository.
# **Who does it impact**: GitHub staff.
on:
issues:
types:
- opened
- transferred
# Required in lieu of `pull_request` so that this workflow can query users in org to determine membership.
pull_request_target:
types:
- opened
permissions:
contents: read
jobs:
check-team-membership:
runs-on: ubuntu-latest
continue-on-error: true
if: github.repository == 'github/docs' && github.actor != 'docs-bot'
steps:
- id: membership_check
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
env:
TEAM_CONTENT_REPO: ${{ secrets.TEAM_CONTENT_REPO }}
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
// Only perform this action with GitHub employees
try {
await github.rest.teams.getMembershipForUserInOrg({
org: 'github',
team_slug: 'employees',
username: context.payload.sender.login,
});
} catch(err) {
// An error will be thrown if the user is not a GitHub employee
// If a user is not a GitHub employee, we should stop here and
// Not send a notification
return
}
// Don't perform this action with Docs team members
try {
await github.rest.teams.getMembershipForUserInOrg({
org: 'github',
team_slug: 'docs',
username: context.payload.sender.login,
});
// If the user is a Docs team member, we should stop here and not send
// a notification
return
} catch(err) {
// An error will be thrown if the user is not a Docs team member
// If a user is not a Docs team member we should continue and send
// the notification
}
const issueNo = context.number || context.issue.number
// Create an issue in our private repo
await github.rest.issues.create({
owner: 'github',
repo: process.env.TEAM_CONTENT_REPO,
title: `@${context.payload.sender.login} confirm that \#${issueNo} should be in the public github/docs repo`,
body: `@${context.payload.sender.login} opened https://github.com/github/docs/issues/${issueNo} publicly in the github/docs repo, instead of the private github/${process.env.TEAM_CONTENT_REPO} repo.\n\n@${context.payload.sender.login}, please confirm that this belongs in the public repo and that no sensitive information was disclosed by commenting below and closing the issue.\n\nIf this was not intentional and sensitive information was shared, please delete https://github.com/github/docs/issues/${issueNo} and notify us in the \#docs-open-source channel.\n\nThanks!`,
labels: ['OS confirmation', 'skip FR board'],
});
core.setOutput('did_warn', 'true')
- name: Send Slack notification if a GitHub employee who isn't on the docs team opens an issue in public
if: ${{ steps.membership_check.outputs.did_warn && github.repository == 'github/docs' }}
uses: someimportantcompany/github-actions-slack-message@a975b440de2bcef178d451cc70d4c1161b5a30cd
with:
channel: ${{ secrets.DOCS_OPEN_SOURCE_SLACK_CHANNEL_ID }}
bot-token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}
text: <@${{github.actor}}> opened https://github.com/github/docs/issues/${{ github.event.number || github.event.issue.number }} publicly on the github/docs repo instead of a private repo. They have been notified via a new issue in the private repo to confirm this was intentional.
- name: Check out repo
if: ${{ failure() && github.event_name != 'pull_request_target' }}
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: ./.github/actions/slack-alert
if: ${{ failure() && github.event_name != 'pull_request_target' }}
with:
slack_channel_id: ${{ secrets.DOCS_ALERTS_SLACK_CHANNEL_ID }}
slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}

View File

@ -0,0 +1,55 @@
name: 'Content Lint Markdown'
# **What it does**: Lints our content markdown to ensure the content matches the specified styleguide.
# **Why we have it**: We want some level of consistency to our content markdown files.
# **Who does it impact**: Docs content writers.
on:
pull_request:
merge_group:
workflow_dispatch:
inputs:
branch:
description: The branch containing the changes we want to lint.
required: true
type: string
default: main
permissions:
contents: read
jobs:
lint-content:
if: github.repository == 'github/docs-internal' || github.repository == 'github/docs'
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
# Fetch 2 commits so tj-actions/changed-files can diff without extra API calls
fetch-depth: 2
- name: Set up Node and dependencies
uses: ./.github/actions/node-npm-setup
- name: Get changed content/data files
id: changed_files
uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5
with:
files: |
content/**
data/**
- name: Print content linter annotations if changed content/data files
if: steps.changed_files.outputs.any_modified == 'true'
env:
CHANGED_FILES: ${{ steps.changed_files.outputs.all_modified_files }}
# If there are errors, using `--print-annotations` will make it
# so it does *not* exit non-zero.
# This is so that all warnings and errors are printed.
run: npm run lint-content -- --print-annotations --paths $CHANGED_FILES
- name: Run content linter if changed content/data files
if: steps.changed_files.outputs.any_modified == 'true'
env:
CHANGED_FILES: ${{ steps.changed_files.outputs.all_modified_files }}
run: npm run lint-content -- --errors-only --paths $CHANGED_FILES

View File

@ -0,0 +1,48 @@
name: 'Check content-linter rules docs'
# **What it does**: Makes sure the content-linter-rules.md is up-to-date.
# **Why we have it**: So what's automated doesn't fall behind
# **Who does it impact**: Docs content.
on:
workflow_dispatch:
pull_request:
paths:
- 'src/content-linter/**'
# In case imported markdownlint rules are updated
- package-lock.json
# In case manual changes are made to the content-linter-rules.md file
- data/reusables/contributing/content-linter-rules.md
# Self-test
- .github/workflows/content-linter-rules-docs.yml
permissions:
contents: read
jobs:
check-content-linter-rules-docs:
runs-on: ubuntu-latest
if: github.repository == 'github/docs-internal' || github.repository == 'github/docs'
steps:
- name: Checkout
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: ./.github/actions/node-npm-setup
- name: Check that content-linter-rules.md is up-to-date
run: npm run generate-content-linter-docs
- name: Fail if it isn't up-to-date
run: |
if [ -n "$(git status --porcelain)" ]; then
git status
git diff
# Some whitespace for the sake of the message below
echo ""
echo ""
echo "content-linter-rules.md is out of date."
echo "Please run 'npm run generate-content-linter-docs' and commit the changes."
exit 1;
fi

View File

@ -0,0 +1,191 @@
name: 'Content pipelines: Update content'
# **What it does**: On a schedule, runs the content pipeline update script for each
# configured entry. The script clones each source repo, detects changes, and
# runs a Copilot agent to update content articles. The workflow handles
# branching, committing, and opening PRs.
# **Why we have it**: Keeps reference documentation in sync with upstream source
# docs without storing copies of those source docs in this repository.
# **Who does it impact**: Docs content writers, docs engineering.
#
# To add a new entry, add it to src/content-pipelines/config.yml and to the matrix
# `include` list below (only `id` is needed). The update logic lives in
# src/content-pipelines/scripts/update.ts, which reads config.yml for all other
# values. Run locally: npx tsx src/content-pipelines/scripts/update.ts --help
on:
schedule:
- cron: '20 16 * * 1-5' # Mon-Fri at 16:20 UTC
workflow_dispatch:
permissions:
contents: write
pull-requests: write
env:
HUSKY: 0
jobs:
update:
if: github.repository == 'github/docs-internal'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
# Each entry only needs `id`. Everything else (source-repo,
# source-path, target-articles, etc.) is read from
# src/content-pipelines/config.yml by the update script.
- id: copilot-cli
# - id: mcp-server
steps:
- name: Checkout docs-internal
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: ./.github/actions/node-npm-setup
- name: Install Copilot CLI
run: npm install -g @github/copilot@prerelease
- name: Derive branch name
id: branch
run: echo "update_branch=docs/content-pipeline-${{ matrix.id }}-update" >> "$GITHUB_OUTPUT"
- name: Check for existing PR
id: check-pr
env:
GH_TOKEN: ${{ github.token }}
UPDATE_BRANCH: ${{ steps.branch.outputs.update_branch }}
run: |
PR_NUMBER=$(gh pr list --head "$UPDATE_BRANCH" --state open --json number --jq '.[0].number // empty' 2>/dev/null || echo "")
echo "pr_number=$PR_NUMBER" >> "$GITHUB_OUTPUT"
- name: Setup branch
id: setup-branch
env:
UPDATE_BRANCH: ${{ steps.branch.outputs.update_branch }}
PR_NUMBER: ${{ steps.check-pr.outputs.pr_number }}
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
if git ls-remote --exit-code --heads origin "$UPDATE_BRANCH" > /dev/null 2>&1; then
git fetch --unshallow origin "$UPDATE_BRANCH" main 2>/dev/null || git fetch origin "$UPDATE_BRANCH" main
git checkout "$UPDATE_BRANCH"
git merge origin/main --no-edit || {
echo "Merge conflict with main — resetting branch to main"
git merge --abort 2>/dev/null || true
git checkout -f main
git branch -D "$UPDATE_BRANCH"
if [ -z "$PR_NUMBER" ]; then
git push origin --delete "$UPDATE_BRANCH" || true
else
echo "Skipping remote branch delete — PR #$PR_NUMBER is open"
echo "force_push=true" >> "$GITHUB_OUTPUT"
fi
git checkout -b "$UPDATE_BRANCH"
}
else
git checkout -b "$UPDATE_BRANCH"
fi
- name: Run content pipeline update script
env:
GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COPILOT_GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_COPILOT }}
run: npx tsx src/content-pipelines/scripts/update.ts --id "${{ matrix.id }}"
- name: Commit changes
id: commit
env:
ID: ${{ matrix.id }}
run: |
git add content/ data/
if git diff --cached --quiet; then
echo "has_changes=false" >> "$GITHUB_OUTPUT"
echo "No documentation changes to commit"
else
git add "src/content-pipelines/state/${ID}.sha"
git commit -m "docs: update ${ID} content from source docs" \
-m "Updated by the content-pipeline-update agent (${ID}) via GitHub Actions." \
-m "Run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
echo "has_changes=true" >> "$GITHUB_OUTPUT"
fi
- name: Push changes
if: steps.commit.outputs.has_changes == 'true'
env:
UPDATE_BRANCH: ${{ steps.branch.outputs.update_branch }}
FORCE_PUSH: ${{ steps.setup-branch.outputs.force_push }}
run: |
if [ "$FORCE_PUSH" = "true" ]; then
echo "Force-pushing to align branch after merge conflict reset"
git push --force-with-lease origin "$UPDATE_BRANCH"
else
git push origin "$UPDATE_BRANCH"
fi
- name: Read source repo info from config
id: source-info
env:
PIPELINE_ID: ${{ matrix.id }}
run: |
SOURCE_REPO=$(yq -r ".[\"${PIPELINE_ID}\"].\"source-repo\"" src/content-pipelines/config.yml)
SOURCE_PATH=$(yq -r ".[\"${PIPELINE_ID}\"].\"source-path\"" src/content-pipelines/config.yml)
echo "source_repo=$SOURCE_REPO" >> "$GITHUB_OUTPUT"
echo "source_path=$SOURCE_PATH" >> "$GITHUB_OUTPUT"
- name: Create or update PR
if: steps.commit.outputs.has_changes == 'true'
env:
GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }}
UPDATE_BRANCH: ${{ steps.branch.outputs.update_branch }}
PIPELINE_ID: ${{ matrix.id }}
SOURCE_REPO: ${{ steps.source-info.outputs.source_repo }}
SOURCE_PATH: ${{ steps.source-info.outputs.source_path }}
run: |
PR_NUMBER="${{ steps.check-pr.outputs.pr_number }}"
PR_TITLE="docs: update ${PIPELINE_ID} content from source docs"
SOURCE_LINK="See the [upstream repo](https://github.com/${SOURCE_REPO}/tree/main/${SOURCE_PATH}) for changes that triggered this update."
if [ -n "$PR_NUMBER" ]; then
echo "PR #$PR_NUMBER already exists"
echo "Ensuring PR #$PR_NUMBER is marked ready for review"
gh pr ready "$PR_NUMBER" || echo "Unable to mark PR #$PR_NUMBER as ready (it may already be ready)"
else
echo "Creating new PR"
PR_BODY="_GitHub Copilot generated this pull request._"$'\n\n'
PR_BODY+="> [!NOTE]"$'\n'
PR_BODY+="> This PR is **automatically generated** by the [content pipeline update workflow](${{ github.server_url }}/${{ github.repository }}/actions/workflows/content-pipelines.yml). Each run adds a new commit with any documentation changes detected."$'\n\n'
PR_BODY+="## What this does"$'\n\n'
PR_BODY+="Runs the \`content-pipeline-update\` agent (${PIPELINE_ID}) against the latest source docs and updates official articles under \`content/\` that have fallen out of sync."$'\n\n'
PR_BODY+="## Source changes"$'\n\n'
PR_BODY+="${SOURCE_LINK}"$'\n\n'
PR_BODY+="## Review"$'\n\n'
PR_BODY+="* Review each commit for accuracy — the agent uses AI, so spot-check important changes"$'\n'
PR_BODY+="* To adjust agent behavior, see [Modifying results](${{ github.server_url }}/${{ github.repository }}/blob/main/src/content-pipelines/README.md#modifying-results)"$'\n'
PR_BODY+="* Once satisfied, merge to keep docs up to date"$'\n'
PR_BODY+="* A new PR will be created on the next run if there are further changes"
gh pr create \
--title "$PR_TITLE" \
--body "$PR_BODY" \
--base main \
--head "$UPDATE_BRANCH" \
--label "workflow-generated,content-pipeline-update,ready-for-doc-review,skip FR board"
fi
- uses: ./.github/actions/slack-alert
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
with:
slack_channel_id: ${{ secrets.DOCS_ALERTS_SLACK_CHANNEL_ID }}
slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}
- uses: ./.github/actions/create-workflow-failure-issue
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
with:
token: ${{ secrets.DOCS_BOT_PAT_BASE }}

View File

@ -0,0 +1,53 @@
# Copilot cloud agent setup steps
#
# This is a special-name workflow recognized by Copilot cloud agent.
# When a cloud agent session starts (via GitHub issue assignment or the
# Copilot UI), these steps run first to bootstrap the development
# environment before the agent begins working.
#
# The workflow_dispatch trigger allows manual testing of the setup steps.
# This is NOT a regular CI workflow — it does not run on push or PR events.
#
# See also:
# .github/copilot-instructions.md — always-on agent instructions
# .github/instructions/ — contextual instruction files
# .github/prompts/ — on-demand prompt files (e.g. /code-review)
name: 'Copilot Setup Steps'
on:
workflow_dispatch:
jobs:
copilot-setup-steps:
runs-on: ubuntu-latest
if: github.repository == 'github/docs-internal' || github.repository == 'github/docs'
permissions:
contents: read
id-token: write
env:
ELASTICSEARCH_URL: http://localhost:9200/
steps:
- name: Checkout code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: ./.github/actions/node-npm-setup
# Search and language test suites require a running Elasticsearch instance.
- uses: ./.github/actions/setup-elasticsearch
with:
token: ${{ secrets.DOCS_BOT_PAT_BASE }}
# docs-internal has early-access content that must be fetched separately.
- uses: ./.github/actions/get-docs-early-access
if: ${{ github.repository == 'github/docs-internal' }}
with:
token: ${{ secrets.DOCS_BOT_PAT_BASE }}
# Many test suites depend on Next.js build artifacts.
- name: Build
run: npm run build
# Populate Elasticsearch with fixture data so search/language tests work.
- name: Index fixtures into the local Elasticsearch
run: npm run index-test-fixtures

View File

@ -0,0 +1,81 @@
name: Copy to API/events issue to docs-content
# **What it does**: Copies an issue in the open source repo to the docs-content repo, comments on and closes the original issue
# **Why we have it**: OpenAPI/GraphQL schema updates cannot be made in the open source repo. Instead, we copy the issue to an internal issue (we do not transfer so that the issue does not disappear for the contributor) and close the original issue.
# **Who does it impact**: Open source and docs-content maintainers
on:
issues:
types:
- labeled
permissions:
contents: read
jobs:
transfer-issue:
name: Transfer issue
runs-on: ubuntu-latest
if: github.event.label.name == 'fix-internally' && github.repository == 'github/docs'
steps:
- name: Check if this run was triggered by a member of the docs team
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
id: triggered-by-member
with:
github-token: ${{secrets.DOCS_BOT_PAT_BASE}}
result-encoding: string
script: |
const triggerer_login = context.payload.sender.login
const teamMembers = await github.request(
`/orgs/github/teams/docs/members?per_page=100`
)
const logins = teamMembers.data.map(member => member.login)
if (logins.includes(triggerer_login)) {
console.log(`This workflow was triggered by ${triggerer_login} (on the docs team).`)
return 'true'
}
console.log(`This workflow was triggered by ${triggerer_login} (not on the docs team), so no action will be taken.`)
return 'false'
- name: Exit if not triggered by a docs team member
if: steps.triggered-by-member.outputs.result == 'false'
run: |
echo Aborting. This workflow must be triggered by a member of the docs team.
exit 1
- name: Create an issue in the docs-content repo
run: |
new_issue_url="$(gh issue create --title "$ISSUE_TITLE" --body "$ISSUE_BODY" --repo github/docs-content --label "workflow-generated")"
echo 'NEW_ISSUE='$new_issue_url >> $GITHUB_ENV
env:
GITHUB_TOKEN: ${{secrets.DOCS_BOT_PAT_BASE}}
ISSUE_TITLE: ${{ github.event.issue.title }}
ISSUE_BODY: ${{ github.event.issue.body }}
- name: Comment on the old issue
run: gh issue comment $OLD_ISSUE --body "Thank you for opening this issue! Updates to this documentation must be made internally. I have copied your issue to an internal issue, so I will close this issue."
env:
GITHUB_TOKEN: ${{secrets.DOCS_BOT_PAT_BASE}}
OLD_ISSUE: ${{ github.event.issue.html_url }}
- name: Close the old issue
run: gh issue close $OLD_ISSUE
env:
GITHUB_TOKEN: ${{secrets.DOCS_BOT_PAT_BASE}}
OLD_ISSUE: ${{ github.event.issue.html_url }}
- name: Comment on the new issue
run: gh issue comment $NEW_ISSUE --body "This issue was originally opened in the open source repo as $OLD_ISSUE"
env:
GITHUB_TOKEN: ${{secrets.DOCS_BOT_PAT_BASE}}
NEW_ISSUE: ${{ env.NEW_ISSUE }}
OLD_ISSUE: ${{ github.event.issue.html_url }}
- name: Check out repo
if: ${{ failure() && github.event_name != 'workflow_dispatch' && github.repository == 'github/docs-internal' }}
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: ./.github/actions/slack-alert
if: ${{ failure() && github.event_name != 'workflow_dispatch' && github.repository == 'github/docs-internal' }}
with:
slack_channel_id: ${{ secrets.DOCS_ALERTS_SLACK_CHANNEL_ID }}
slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}

View File

@ -0,0 +1,44 @@
name: Count translation corruptions
# **What it does**: Generates a summary of Liquid corruptions per language.
# **Why we have it**: For insights into the state of translations and things we can do to fix them
# **Who does it impact**: Engineering
on:
workflow_dispatch:
pull_request:
paths:
- src/languages/scripts/count-translation-corruptions.ts
- src/languages/lib/correct-translation-content.ts
- .github/workflows/count-translation-corruptions.yml
- .github/actions/node-npm-setup/action.yml
- .github/actions/clone-translations/action.yml
- 'package**.json'
permissions:
contents: read
jobs:
count-translation-corruptions:
if: github.repository == 'github/docs-internal'
runs-on: ubuntu-latest
steps:
- name: Checkout English repo
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
# Using a PAT is necessary so that the new commit will trigger the
# CI in the PR. (Events from GITHUB_TOKEN don't trigger new workflows.)
token: ${{ secrets.DOCS_BOT_PAT_BASE }}
# It's important because translations are often a bit behind.
# So if a translation is a bit behind, it might still be referencing
# an asset even though none of the English content does.
- name: Clone all translations
uses: ./.github/actions/clone-translations
with:
token: ${{ secrets.DOCS_BOT_PAT_BASE }}
- uses: ./.github/actions/node-npm-setup
- name: Run count
run: npm run count-translation-corruptions

View File

@ -0,0 +1,171 @@
name: Create a PR to add an entry to the CHANGELOG.md file in this repo
# **What it does**: If a member of the github org posts a changelog comment, it creates a PR to update the CHANGELOG.md file.
# **Why we have it**: This surfaces docs changelog details publicly.
# **Who does it impact**: GitHub users and staff.
on:
issue_comment:
types: [created]
workflow_dispatch:
permissions:
contents: write
pull-requests: write
env:
CHANGELOG_FILE: CHANGELOG.md
CHANGELOG_FILE_URL: https://github.com/github/docs-internal/blob/main/CHANGELOG.md
jobs:
docs-changelog-pr:
if: ${{ github.repository == 'github/docs-internal' && github.event.issue.pull_request }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: 'Ensure ${{ env.CHANGELOG_FILE }} exists'
run: |
if [ ! -f ${{ env.CHANGELOG_FILE }} ]; then
echo "${{ env.CHANGELOG_FILE }} is missing at the root of the repository."
exit 1
fi
- name: Check that the user belongs to the github org
id: hubber_check
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
try {
await github.rest.teams.getMembershipForUserInOrg({
org: 'github',
team_slug: 'employees',
username: context.payload.sender.login,
});
core.exportVariable('CONTINUE_WORKFLOW', 'true');
} catch(err) {
core.info("Workflow triggered by a comment, but the commenter is not a Hubber. Exiting.");
core.exportVariable('CONTINUE_WORKFLOW', 'false');
}
- name: Check if comment starts with '## Changelog summary'
if: env.CONTINUE_WORKFLOW == 'true'
id: check_summary
env:
COMMENT_BODY: ${{ github.event.comment.body }}
run: |
# Get the first line of the comment and trim the leading/trailing whitespace:
FIRST_LINE=$(printf "%s\n" "$COMMENT_BODY" | head -n1 | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
if [[ "$FIRST_LINE" != '## Changelog summary' ]]; then
echo "FIRST_LINE=|$FIRST_LINE|"
echo "The pull request comment is not a changelog summary. Exiting."
echo "CONTINUE_WORKFLOW=false" >> $GITHUB_ENV
fi
- name: Create changelog text
if: env.CONTINUE_WORKFLOW == 'true'
id: create_text
env:
COMMENT_BODY: ${{ github.event.comment.body }}
run: |
set -euo pipefail
DATE=$(date +"**%-d %B %Y**")
BODY="$(printf "%s\n" "$COMMENT_BODY" | tail -n +2)"
CHANGELOG_TEXT="$(printf "%s\n" "$BODY" | awk '/^:writing_hand:/{exit} {print}')"
{
echo "$DATE"
echo -e "$CHANGELOG_TEXT\n<hr>"
} > changelog_entry.txt
- name: Set up git
if: env.CONTINUE_WORKFLOW == 'true'
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Prepare branch
if: env.CONTINUE_WORKFLOW == 'true'
run: |
BRANCH="changelog-update-$(date +%s)"
echo "BRANCH=$BRANCH" >> $GITHUB_ENV
git checkout -b "$BRANCH"
# Insert new changelog entry after the first heading, as follows:
# Print the first line of the existing CHANGELOG.md file into a `tmp` file, followed by an empty line.
# Then, print the contents of `changelog_entry.txt` into the `tmp` file.
# Then, print the rest of the existing CHANGELOG.md file into the `tmp` file.
# Finally, replace the existing CHANGELOG.md file with the `tmp` file.
awk 'NR==1{print; print ""; while ((getline line < "changelog_entry.txt") > 0) print line; next}1' CHANGELOG.md > tmp && mv tmp CHANGELOG.md
git add CHANGELOG.md
git commit -m "Update changelog for $(head -n1 changelog_entry.txt)"
git push origin "$BRANCH"
- name: Create a pull request
if: env.CONTINUE_WORKFLOW == 'true'
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
id: create_pull_request
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
const { data: pullRequest } = await github.rest.pulls.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `Update docs changelog (for PR #${context.payload.issue.number})`,
body: `### Automated docs changelog update\n\n**Purpose:** Update the <code>[${{ env.CHANGELOG_FILE }}](${{ env.CHANGELOG_FILE_URL }})</code> file with details of a recent docs change.\n\nThis PR is an automated update, generated by the <code>create-changelog-pr.yml</code> Actions workflow as a result of a "Changelog summary" comment being added to [PR #${context.payload.issue.number}](${context.payload.issue.html_url}).\n\n**Notes for reviewer**:\n- This change to the <code>[${{ env.CHANGELOG_FILE }}](${{ env.CHANGELOG_FILE_URL }})</code> file will be synced to the public docs site, so make sure that the content of the entry is appropriate for public consumption. If the content is wholly inappropriate for public consumption, then this PR can be closed.\n- Make sure the format of this changelog entry is consistent with the other entries in the file.\n\n<details><summary>Original PR comment posted by @${context.payload.comment.user.login}, using the <code>/changelog</code> slash command:</summary>\n\n${context.payload.comment.body}</details>`,
head: process.env.BRANCH,
base: 'main'
});
core.setOutput('pull-request-number', pullRequest.number);
core.setOutput('pull-request-url', pullRequest.html_url);
- name: Add 'ready-for-doc-review' and 'skip FR board' labels to PR
if: env.CONTINUE_WORKFLOW == 'true'
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
env:
# Get the number of the PR that was just created:
PULL_REQUEST_NUMBER: ${{ steps.create_pull_request.outputs.pull-request-number }}
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: Number(process.env.PULL_REQUEST_NUMBER),
labels: ['ready-for-doc-review','skip FR board']
});
- name: Assign PR to commenter
if: env.CONTINUE_WORKFLOW == 'true'
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3
env:
# Reuse the PR number captured earlier
PULL_REQUEST_NUMBER: ${{ steps.create_pull_request.outputs.pull-request-number }}
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
try {
const username = context.payload.comment.user.login;
await github.rest.issues.addAssignees({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: Number(process.env.PULL_REQUEST_NUMBER),
assignees: [username]
});
} catch (err) {
core.info(`Failed to assign PR to @${context.payload.comment.user.login}: ${err.message}`);
}
- uses: ./.github/actions/slack-alert
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
with:
slack_channel_id: ${{ secrets.DOCS_ALERTS_SLACK_CHANNEL_ID }}
slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}
- uses: ./.github/actions/create-workflow-failure-issue
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
with:
token: ${{ secrets.DOCS_BOT_PAT_BASE }}

View File

@ -0,0 +1,168 @@
name: Delete orphan translation files
# **What it does**:
# Compares content & data files left in each translation that aren't
# in docs-internal. Then creates a PR to delete these files.
# **Why we have it**:
# When Juno dumps to each translation repo it can not account for the
# fact that files in docs-internal get moved or deleted. So the
# sum total of files constantly grows.
# This leads to excess files in each translation repo that are not
# ever used but has to be put into every production build.
# **Who does it impact**: Docs engineering
on:
workflow_dispatch:
schedule:
- cron: '20 16 * * 1' # Run every Monday at 16:20 UTC / 8:20 PST
permissions:
contents: write
jobs:
delete-orphan-translation-files:
if: github.repository == 'github/docs-internal'
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- language: zh
language_dir: translations/zh-cn
language_repo: github/docs-internal.zh-cn
- language: es
language_dir: translations/es-es
language_repo: github/docs-internal.es-es
- language: pt
language_dir: translations/pt-br
language_repo: github/docs-internal.pt-br
- language: ru
language_dir: translations/ru-ru
language_repo: github/docs-internal.ru-ru
- language: ja
language_dir: translations/ja-jp
language_repo: github/docs-internal.ja-jp
- language: fr
language_dir: translations/fr-fr
language_repo: github/docs-internal.fr-fr
- language: de
language_dir: translations/de-de
language_repo: github/docs-internal.de-de
- language: ko
language_dir: translations/ko-kr
language_repo: github/docs-internal.ko-kr
steps:
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Checkout the language-specific repo
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
repository: ${{ matrix.language_repo }}
token: ${{ secrets.DOCS_BOT_PAT_BASE }}
path: ${{ matrix.language_dir }}
- uses: ./.github/actions/node-npm-setup
- name: Delete orphan files
run: |
npm run delete-orphan-translation-files -- ${{ matrix.language_dir }}
- name: Debug deleted files
working-directory: ${{ matrix.language_dir }}
run: git status
- name: Git config
working-directory: ${{ matrix.language_dir }}
run: |
git config --global user.name "docs-bot"
git config --global user.email "77750099+docs-bot@users.noreply.github.com"
- name: Git commit and push, create and merge PR
working-directory: ${{ matrix.language_dir }}
env:
# Needed for gh
GH_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }}
run: |
# If nothing to commit, exit now. It's fine. No orphans.
changes=$(git diff --name-only | wc -l)
untracked=$(git status --untracked-files --short | wc -l)
if [[ $changes -eq 0 ]] && [[ $untracked -eq 0 ]]; then
echo "There are no changes to commit or untracked files. Exiting."
exit 0
fi
# Create a general retry function that retries and sleeps
retry_command() {
local max_attempts=3
local attempt=1
while [ $attempt -le $max_attempts ]; do
echo "Attempt $attempt: $@"
"$@" && return 0
((attempt++))
sleep 3 # You can adjust the sleep duration as needed
done
echo "Max attempts reached. Command failed after $max_attempts attempts."
return 1
}
git status
current_timestamp=$(date '+%Y-%m-%d-%H%M%S')
branch_name="delete-orphan-files-$current_timestamp"
git checkout -b "$branch_name"
current_daystamp=$(date '+%Y-%m-%d')
git commit -a -m "Delete orphan files ($current_daystamp)"
git push origin "$branch_name"
# Create PR
echo "Creating pull request..."
gh pr create \
--title "Delete orphan files ($current_daystamp)" \
--body '👋 humans. This PR was generated from docs-internal/.github/workflows/delete-orphan-translation-files.yml.
' \
--repo "${{ matrix.language_repo }}" \
--label "workflow-generated" \
--head=$branch_name
echo "Merge created PR..."
# Prefer enabling auto-merge so the PR waits for any required
# checks before merging. If auto-merge can't be enabled — usually
# because all required checks completed before this step ran and
# the PR is already immediately mergeable — fall back to a direct
# merge. GitHub returns one of these misleading errors in that
# case: "Branch does not have required protected branch rules",
# "Pull request is in unstable status", or "Pull request is not
# in a mergeable state".
auto_merge_err=$(mktemp)
trap 'rm -f "$auto_merge_err"' EXIT
if retry_command gh pr merge --merge --auto --delete-branch "$branch_name" 2>"$auto_merge_err"; then
:
else
cat "$auto_merge_err"
if grep -qE "does not have required protected branch rules|unstable status|Pull request is not in a mergeable state" "$auto_merge_err"; then
echo "Auto-merge unavailable; PR appears immediately mergeable. Falling back to direct merge."
retry_command gh pr merge --merge --delete-branch "$branch_name"
else
echo "Auto-merge failed with an unexpected error."
exit 1
fi
fi
- uses: ./.github/actions/slack-alert
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
with:
slack_channel_id: ${{ secrets.DOCS_ALERTS_SLACK_CHANNEL_ID }}
slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}
- uses: ./.github/actions/create-workflow-failure-issue
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
with:
token: ${{ secrets.DOCS_BOT_PAT_BASE }}

View File

@ -0,0 +1,54 @@
name: Add docs-reviewers request to the docs-content review board
# **What it does**: Adds PRs in github/github and github/audit-log-allowlists that requested a review from docs-reviewers to the docs-content review board
# **Why we have it**: To catch docs-reviewers requests in github/audit-log-allowlists
# **Who does it impact**: docs-content maintainers
on:
workflow_dispatch:
schedule:
- cron: '20 16 * * 1-5' # Run Mon-Fri at 16:20 UTC / 8:20 PST
permissions:
contents: read
jobs:
add-requests-to-board:
name: Add requests to board
if: ${{ github.repository == 'github/docs-internal' }}
runs-on: ubuntu-latest
steps:
- name: Check out repo content
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Setup Node.js
uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
with:
node-version-file: 'package.json'
cache: npm
- name: Install dependencies
run: npm ci
- name: Run script for audit-log-allowlists
run: |
npm run fr-add-docs-reviewers-requests
env:
TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }}
PROJECT_NUMBER: 2936
ORGANIZATION: 'github'
REPO: 'audit-log-allowlists'
REVIEWER: 'docs-reviewers'
FEATURE: 'Audit log event descriptions'
- uses: ./.github/actions/slack-alert
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
with:
slack_channel_id: ${{ secrets.DOCS_ALERTS_SLACK_CHANNEL_ID }}
slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}
- uses: ./.github/actions/create-workflow-failure-issue
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
with:
token: ${{ secrets.DOCS_BOT_PAT_BASE }}

View File

@ -0,0 +1,66 @@
name: Don't delete assets
# **What it does**:
# If the PR (against main) involves deletion of assets, if any of
# them are deletions or renames, post a comment, and ultimately
# fail the check.
# **Why we have it**:
# If you delete the reference to an image, the English content is fine
# because it no longer tries to serve an image that doesn't exist.
# But this is not the case for translations.
# **Who does it impact**: Docs content.
on:
workflow_dispatch:
pull_request:
branches:
- main
paths:
- 'assets/**'
- '.github/workflows/dont-delete-assets.yml'
permissions:
contents: read
pull-requests: write
jobs:
dont-delete-assets:
# It's 'docs-bot' that creates those PR from "Delete orphaned assets"
if: github.event.pull_request.user.login != 'docs-bot' && (github.repository == 'github/docs-internal' || github.repository == 'github/docs')
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: ./.github/actions/node-npm-setup
- name: Get comment markdown
id: comment
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npm run deleted-assets-pr-comment
- name: Find possible previous comment
if: ${{ steps.comment.outputs.markdown != '' }}
uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad
id: findComment
with:
issue-number: ${{ github.event.number }}
comment-author: 'github-actions[bot]'
body-includes: '<!-- DELETED_ASSETS -->'
- name: Update comment
if: ${{ steps.comment.outputs.markdown != '' }}
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9
with:
comment-id: ${{ steps.findComment.outputs.comment-id }}
issue-number: ${{ github.event.number }}
body: ${{ steps.comment.outputs.markdown }}
edit-mode: replace
- name: Ultimately fail the workflow for attention
if: ${{ steps.comment.outputs.markdown != '' }}
run: |
echo "More than 1 asset image was deleted as part of this PR."
echo "See posted PR commented about how to get them back."
exit 1

View File

@ -0,0 +1,66 @@
name: Don't delete features
# **What it does**:
# If the PR (against main) involves deletion of features, if any of
# them are deletions or renames, post a comment, and ultimately
# fail the check.
# **Why we have it**:
# If you delete the reference to an image, the English content is fine
# because it no longer tries to use the feature that doesn't exist.
# But this is not the case for translations.
# **Who does it impact**: Docs content.
on:
workflow_dispatch:
pull_request:
branches:
- main
paths:
- 'data/features/**'
- .github/workflows/dont-delete-features.yml
permissions:
contents: read
pull-requests: write
jobs:
dont-delete-features:
# It's 'docs-bot' that creates those PR from "Delete orphaned features"
if: github.event.pull_request.user.login != 'docs-bot' && (github.repository == 'github/docs-internal' || github.repository == 'github/docs')
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: ./.github/actions/node-npm-setup
- name: Get comment markdown
id: comment
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npm run deleted-features-pr-comment
- name: Find possible previous comment
if: ${{ steps.comment.outputs.markdown != '' }}
uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad
id: findComment
with:
issue-number: ${{ github.event.number }}
comment-author: 'github-actions[bot]'
body-includes: '<!-- DELETED_FEATURES -->'
- name: Update comment
if: ${{ steps.comment.outputs.markdown != '' }}
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9
with:
comment-id: ${{ steps.findComment.outputs.comment-id }}
issue-number: ${{ github.event.number }}
body: ${{ steps.comment.outputs.markdown }}
edit-mode: replace
- name: Ultimately fail the workflow for attention
if: ${{ steps.comment.outputs.markdown != '' }}
run: |
echo "More than 1 feature was deleted as part of this PR."
echo "See posted PR commented about how to get them back."
exit 1

View File

@ -0,0 +1,81 @@
name: Enterprise date updater
# **What it does**: Runs on a schedule to update
# src/ghes-releases/lib/enterprise-dates.json.
# **Why we have it**: The src/ghes-releases/lib/enterprise-dates.json
# file needs to be up-to-date for the
# Used to display deprecation banner dates and as a reference
# for all past server release numbers.
# **Who does it impact**: Docs engineering, docs content.
on:
workflow_dispatch:
schedule:
- cron: '20 16 * * 1' # Run every Monday at 16:20 UTC / 8:20 PST
permissions:
contents: write
pull-requests: write
jobs:
open_enterprise_issue:
name: Enterprise date updater
if: github.repository == 'github/docs-internal'
runs-on: ubuntu-latest
steps:
- name: Checkout repository code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: ./.github/actions/node-npm-setup
- name: Run src/ghes-releases/scripts/update-enterprise-dates.ts
run: npm run update-enterprise-dates
env:
GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }}
- name: Create pull request
id: create-pull-request
uses: peter-evans/create-pull-request@98357b18bf14b5342f975ff684046ec3b2a07725 # pin @v8.0.0
env:
# Disable pre-commit hooks; they don't play nicely here
HUSKY: '0'
with:
# need to use a token with repo and workflow scopes for this step
token: ${{ secrets.DOCS_BOT_PAT_BASE }}
commit-message: '🤖 ran src/ghes-releases/scripts/update-enterprise-dates.ts'
title: 🤖 src/ghes-releases/lib/enterprise-dates.json update
body:
"Hello! The GitHub Enterprise Server release dates have changed.\n\n
If CI passes, this PR will be auto-merged. :green_heart:\n\n
If CI does not pass or other problems arise, contact #docs-engineering on slack.\n\nThis PR was 🤖-crafted by `.github/workflows/enterprise-dates.yml`. 🧶"
branch: enterprise-server-dates-update
delete-branch: true
- name: Enable GitHub auto-merge
if: ${{ steps.create-pull-request.outputs.pull-request-number }}
env:
GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }}
AUTOMERGE_PR_NUMBER: ${{ steps.create-pull-request.outputs.pull-request-number }}
run: npm run enable-automerge
- if: ${{ failure() }}
name: Delete remote branch (if previous steps failed)
run: git push origin --delete enterprise-server-dates-update
- if: ${{ steps.create-pull-request.outputs.pull-request-number }}
name: Approve
uses: juliangruber/approve-pull-request-action@dcc4effb325c0b503408619918d56e40653dcc91
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
number: ${{ steps.create-pull-request.outputs.pull-request-number }}
- uses: ./.github/actions/slack-alert
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
with:
slack_channel_id: ${{ secrets.DOCS_ALERTS_SLACK_CHANNEL_ID }}
slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}
- uses: ./.github/actions/create-workflow-failure-issue
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
with:
token: ${{ secrets.DOCS_BOT_PAT_BASE }}

View File

@ -0,0 +1,45 @@
name: Open Enterprise release or deprecation issue
# **What it does**: Checks if there is an Enterprise release or deprecation upcoming, and if so, opens an issue with the tasks to be completed.
# **Why we have it**: GHES releases and deprecations run on a predictable schedule, so we can automate some of the project management aspects.
# **Who does it impact**: Docs engineering, docs content.
on:
workflow_dispatch:
schedule:
- cron: '20 16 * * 1' # Run every Monday at 16:20 UTC / 8:20 PST
permissions:
contents: read
jobs:
open_enterprise_issue:
name: Open Enterprise issue
if: github.repository == 'github/docs-internal'
runs-on: ubuntu-latest
steps:
- name: Checkout repository code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: ./.github/actions/node-npm-setup
- name: Create an enterprise release issue
run: npm run create-enterprise-issue -- release
env:
GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }}
- name: Create an enterprise deprecation issue
run: npm run create-enterprise-issue -- deprecation
env:
GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }}
- uses: ./.github/actions/slack-alert
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
with:
slack_channel_id: ${{ secrets.DOCS_ALERTS_SLACK_CHANNEL_ID }}
slack_token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}
- uses: ./.github/actions/create-workflow-failure-issue
if: ${{ failure() && github.event_name != 'workflow_dispatch' }}
with:
token: ${{ secrets.DOCS_BOT_PAT_BASE }}

View File

@ -0,0 +1,25 @@
name: Expertise Required label message
# **What it does**: Adds a bot comment stating a certain level of expertise is required to a docs-content issue when the `contributor-expertise-required` label is applied
# **Why we have it**: We need a method to surface a message denoting if an issue requires a certain level of expertise in order to be resolved
# **Who does it impact**: Open Source and Hubbers
on:
issues:
types:
- labeled
jobs:
job:
name: Comment on issue with expertise required message
runs-on: ubuntu-latest
permissions:
issues: write
if: github.event.label.name == 'contributor-expertise-required' && github.repository == 'github/docs'
steps:
- name: Comment on issue
env:
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
issue: ${{ github.event.issue.html_url }}
run: |
gh issue comment $issue --body 'Addressing this issue will require additional expertise from the contributor. Please make sure to review the issue carefully before opening a PR and ask any questions you might have in the issue.'

View File

@ -0,0 +1,78 @@
name: Feedback prompt for non-Docs team contributors when a PR is closed
on:
pull_request:
types: [closed]
permissions:
contents: read
pull-requests: write
jobs:
comment-on-pr:
# This workflow should only run on the 'github/docs-internal' repository because it posts a feedback request
# to non-Docs team contributors when their PR is merged into the main branch.
# The feedback request asks contributors to leave feedback on their contributing experience in Slack.
if: github.repository == 'github/docs-internal' && github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'main'
runs-on: ubuntu-latest
steps:
- name: Check if PR author is in docs-content team
id: check_team
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
try {
const pr = context.payload.pull_request;
await github.rest.teams.getMembershipForUserInOrg({
org: 'github',
team_slug: 'docs-content',
username: pr.user.login,
});
// Author is in the team. Do nothing!
} catch(err) {
// Author not in team
core.exportVariable('NON_DOCS_HUBBER', 'true');
}
- name: Post changelog instructions comment
if: env.NON_DOCS_HUBBER == 'true'
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
const pr = context.payload.pull_request;
const prAuthor = pr.user.login;
const assignees = (pr.assignees ?? [])
.filter(a => a.login.toLowerCase() !== "copilot")
.map(a => "@" + a.login)
.join(" ");
let commentBody;
if (assignees) {
commentBody =
"👋 " + assignees +
" - Thanks for your contribution! " +
"If you think something could be improved about the contributor experience, please post in `#docs-contributor-feedback` on Slack.";
} else if (prAuthor.toLowerCase() !== "copilot") {
commentBody =
"👋 @" + prAuthor +
" - Thanks for your contribution! " +
"If you think something could be improved about the contributor experience, please post in `#docs-contributor-feedback` on Slack.";
} else {
// nobody to mention!
commentBody =
"👋 Thanks for your contribution! " +
"If you think something could be improved about the contributor experience, please post in `#docs-contributor-feedback` on Slack.";
}
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
body: commentBody
});

View File

@ -0,0 +1,56 @@
name: Add maintenance PRs to the docs-content FR project v2
# **What it does**: Adds docs-internal pull requests authored by docs-bot to the docs-content FR project v2
# **Why we have it**: So we don't lose track of maintenance pull requests for docs-content to review
# **Who does it impact**: Docs content
on:
pull_request:
types:
- reopened
- opened
- ready_for_review
permissions:
contents: read
pull-requests: write
repository-projects: write
jobs:
first-responder-triage-pr:
name: Add maintenance PR to FR project v2
if: github.repository == 'github/docs-internal' && github.event.pull_request.draft == false && github.event.pull_request.user.id == 77750099 && github.event.pull_request.head.ref != 'repo-sync' && !contains(github.event.pull_request.labels.*.name, 'skip FR board')
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
# Add to the FR project
# and set type to "Maintenance"
# and set date to now
- name: Triage to docs-content FR project
env:
GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }}
PR_URL: ${{ github.event.pull_request.html_url }}
PROJECT_NUMBER: 11672
PROJECT_ID: PVT_kwDNJr_OAGNkBg
TYPE_FIELD_ID: PVTSSF_lADNJr_OAGNkBs4D-Nyn
DATE_FIELD_ID: PVTF_lADNJr_OAGNkBs4D-N1h
TYPE_FIELD_VALUE: 3f142cf2
run: |
echo "Adding item to project..."
ITEM_ID=$(gh project item-add $PROJECT_NUMBER --owner github --url $PR_URL --format json | jq .id)
echo "Editing type..."
gh project item-edit --project-id $PROJECT_ID --id $ITEM_ID --field-id $TYPE_FIELD_ID --single-select-option-id $TYPE_FIELD_VALUE
echo "Editing date..."
DATE=$(date '+%Y-%m-%d')
gh project item-edit --project-id $PROJECT_ID --id $ITEM_ID --field-id $DATE_FIELD_ID --date $DATE
echo "done editing"

View File

@ -0,0 +1,262 @@
name: Generate code scanning query lists
# **What it does**: This workflow is currently run manually approximately every two weeks as part
# of the release process for the CodeQL CLI. We hope to automate this in the future
# When run, this workflow generates updated query lists with data from the codeql
# repository, and creates a pull request if there are updates.
# **Why we have it**: So we can automate CodeQL query tables and show code scanning users the built in queries.
# **Who does it impact**: Anyone making CodeQL query suite changes in `github/codeql`, and wanting to get them published on the docs site.
on:
workflow_dispatch:
inputs:
SOURCE_BRANCH:
description: 'Branch to pull the source files from in the codeql repo (for example codeql-cli-2.x.x).'
type: string
required: true
default: 'main'
pull_request:
paths:
- .github/workflows/generate-code-scanning-query-lists.yml
- src/codeql-queries/scripts/generate-code-scanning-query-list.ts
- src/codeql-queries/scripts/generate-code-quality-query-list.ts
- .github/actions/install-cocofix/action.yml
permissions:
contents: read
jobs:
generate-security-query-lists:
if: github.repository == 'github/docs-internal'
runs-on: ubuntu-latest
steps:
- name: Checkout repository code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: ./.github/actions/node-npm-setup
- name: Checkout codeql repo
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
repository: github/codeql
path: codeql
ref: ${{ inputs.SOURCE_BRANCH || 'main' }}
- name: Get the codeql SHA being synced
id: codeql
shell: bash
run: |
cd codeql
OPENAPI_COMMIT_SHA=$(git rev-parse HEAD)
echo "OPENAPI_COMMIT_SHA=$OPENAPI_COMMIT_SHA" >> $GITHUB_OUTPUT
echo "Copied files from github/codeql repo. Commit SHA: $OPENAPI_COMMIT_SHA"
- name: Download CodeQL CLI
# Look under the `codeql` directory, as this is where we checked out the `github/codeql` repo
uses: ./codeql/.github/actions/fetch-codeql
- name: Test CodeQL CLI Download
shell: bash
run: codeql --version
# "Server for running multiple commands while avoiding repeated JVM initialization."
# Having started this should speed up the execution of the various
# CLI calls of the executable.
- name: Start CodeQL CLI server in the background
shell: bash
run: |
codeql execute cli-server &
sleep 3
codeql --version
- uses: ./.github/actions/install-cocofix
with:
token: ${{ secrets.DOCS_BOT_PAT_BASE }}
- name: Build code scanning security query lists
shell: bash
run: |
for lang in "actions" "cpp" "csharp" "go" "java" "javascript" "python" "ruby" "rust" "swift"; do
echo "Generating code scanning query list for $lang"
npm run generate-code-scanning-query-list -- \
--verbose \
--codeql-path codeql \
--codeql-dir codeql \
-o data/reusables/code-scanning/codeql-query-tables/$lang.md \
$lang
done
- name: Upload security query lists
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: security-query-lists
path: data/reusables/code-scanning/codeql-query-tables/
generate-quality-query-lists:
if: github.repository == 'github/docs-internal'
runs-on: ubuntu-latest
steps:
- name: Checkout repository code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- uses: ./.github/actions/node-npm-setup
- name: Checkout codeql repo
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
repository: github/codeql
path: codeql
ref: ${{ inputs.SOURCE_BRANCH || 'main' }}
- name: Get the codeql SHA being synced
id: codeql
shell: bash
run: |
cd codeql
OPENAPI_COMMIT_SHA=$(git rev-parse HEAD)
echo "OPENAPI_COMMIT_SHA=$OPENAPI_COMMIT_SHA" >> $GITHUB_OUTPUT
echo "Copied files from github/codeql repo. Commit SHA: $OPENAPI_COMMIT_SHA"
- name: Download CodeQL CLI
# Look under the `codeql` directory, as this is where we checked out the `github/codeql` repo
uses: ./codeql/.github/actions/fetch-codeql
- name: Test CodeQL CLI Download
shell: bash
run: codeql --version
# "Server for running multiple commands while avoiding repeated JVM initialization."
# Having started this should speed up the execution of the various
# CLI calls of the executable.
- name: Start CodeQL CLI server in the background
shell: bash
run: |
codeql execute cli-server &
sleep 3
codeql --version
- name: Build code quality query lists
shell: bash
run: |
for lang in "csharp" "go" "java" "javascript" "python" "ruby"; do
echo "Generating code quality query list for $lang"
npm run generate-code-quality-query-list -- \
--verbose \
--codeql-path codeql \
--codeql-dir codeql \
-o data/reusables/code-quality/codeql-query-tables/$lang.md \
$lang
done
- name: Upload quality query lists
uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
with:
name: quality-query-lists
path: data/reusables/code-quality/codeql-query-tables/
create-pull-request:
if: github.repository == 'github/docs-internal'
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
needs: [generate-security-query-lists, generate-quality-query-lists]
steps:
- name: Checkout repository code
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
- name: Checkout codeql repo
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
repository: github/codeql
path: codeql
ref: ${{ inputs.SOURCE_BRANCH || 'main' }}
- name: Get the codeql SHA being synced
id: codeql
shell: bash
run: |
cd codeql
OPENAPI_COMMIT_SHA=$(git rev-parse HEAD)
echo "OPENAPI_COMMIT_SHA=$OPENAPI_COMMIT_SHA" >> $GITHUB_OUTPUT
echo "Copied files from github/codeql repo. Commit SHA: $OPENAPI_COMMIT_SHA"
- name: Download security query lists
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
with:
name: security-query-lists
path: data/reusables/code-scanning/codeql-query-tables/
- name: Download quality query lists
uses: actions/download-artifact@70fc10c6e5e1ce46ad2ea6f2b72d43f7d47b13c3 # v8.0.0
with:
name: quality-query-lists
path: data/reusables/code-quality/codeql-query-tables/
- name: Insight into diff
shell: bash
run: |
git diff
- name: Create pull request
env:
GITHUB_TOKEN: ${{ secrets.DOCS_BOT_PAT_BASE }}
DRY_RUN: ${{ github.event_name == 'pull_request'}}
shell: bash
run: |
# When we started, we downloaded the CodeQL CLI here in this workflow.
# We have no intention of checking that in but we also don't want
# `git status ...` to show it as an untracked file.
rm -fr ./codeql
# If nothing to commit, exit now. It's fine. No orphans.
changes=$(git diff --name-only | wc -l)
untracked=$(git status --untracked-files --short | wc -l)
if [[ $changes -eq 0 ]] && [[ $untracked -eq 0 ]]; then
echo "There are no changes to commit after running the generation and conversion scripts. Exiting..."
exit 0
fi
git config --global user.name "docs-bot"
git config --global user.email "77750099+docs-bot@users.noreply.github.com"
branchname=codeql-query-tables-${{ steps.codeql.outputs.OPENAPI_COMMIT_SHA }}
# Exit if the branch already exists. Since the actions/checkout fetch-depth is 1,
# it doesn't "know" about branches locally, so we need to manually list them.
branchExists=$(git ls-remote --heads origin refs/heads/$branchname | wc -l)
# When run on a pull_request, we're just testing the tooling.
# Exit before it actually pushes the possible changes.
if [ "$DRY_RUN" = "true" ]; then
echo "Dry-run mode when run in a pull request"
echo "See the 'Insight into diff' step for the changes it would create PR about."
exit 0
fi
if [ $branchExists -ne 0 ]; then
echo "Branch $branchname already exists in the remote repository."
exit 0
else
git checkout -b $branchname
fi
git add data/reusables/code-scanning/codeql-query-tables
git add data/reusables/code-quality/codeql-query-tables
git commit -m "Update CodeQL query tables"
git push -u origin $branchname
echo "Creating pull request..."
gh pr create \
--title "Update CodeQL query tables" \
--repo github/docs-internal \
--label "codeql-query-tables,skip FR board,ready-for-doc-review,workflow-generated" \
--body '👋 humans. This PR updates the **CodeQL query table reusables** with the latest changes in preparation for the next **CodeQL CLI** release. (Synced from codeql@${{ steps.codeql.outputs.OPENAPI_COMMIT_SHA }})
No action is required from the first responder for the Docs content team. This PR is automatically added to the Docs content review board. Any writer can review this by checking that the PR looks sensible. If CI does not pass or other problems arise, contact #docs-engineering on slack.
When the DRI for the CodeQL CLI release is ready to publish, they will ask us to merge this PR in #docs-content.'

View File

@ -0,0 +1,31 @@
# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
name: Node.js CI
on:
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18.x, 20.x, 22.x]
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
steps:
- uses: actions/checkout@v4
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm run build --if-present
- run: npm test

View File

@ -0,0 +1,173 @@
name: Test
# **What it does**: Runs our tests.
# **Why we have it**: We want our tests to pass before merging code.
# **Who does it impact**: Docs engineering, open-source engineering contributors.
on:
workflow_dispatch:
merge_group:
pull_request:
permissions:
contents: read
pull-requests: read
# This allows a subsequently queued workflow run to interrupt previous runs
concurrency:
group: '${{ github.workflow }} @ ${{ github.event.pull_request.head.label || github.head_ref || github.ref }}'
cancel-in-progress: true
env:
# Setting this will activate the vitest tests that depend on actually
# sending real search queries to Elasticsearch
ELASTICSEARCH_URL: http://localhost:9200/
jobs:
test:
name: ${{ matrix.name }}
if: github.repository == 'github/docs-internal' || github.repository == 'github/docs'
runs-on: ubuntu-latest
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
# Note that *if you add* to this, remember to also add that
# to the **required checks** in the branch protection rules.
name:
# src/ directory
- archives
- article-api
- assets
- audit-logs
- automated-pipelines
# - bookmarklets
# - code-scanning
# - codeql-cli
- color-schemes
- content-linter
- content-render
- data-directory
# - dev-toc
- early-access
- events
- fixtures
- frame
- github-apps
- graphql
- landings
- languages
# - links
- observability
# - open-source
# - pages
- products
- redirects
- release-notes
- rest
- search
- secret-scanning
- shielding
# - tests
# - tools
- versions
- webhooks
- workflows
# The languages suite only runs on docs-internal
isPrivateRepo:
- ${{ github.repository == 'github/docs-internal' }}
exclude:
- name: languages
isPrivateRepo: false
steps:
# Each of these ifs needs to be repeated at each step to make sure the required check still runs
# Even if if doesn't do anything
- name: Check out repo
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
# Fetch 2 commits so tj-actions/changed-files can diff without extra API calls
fetch-depth: 2
- uses: ./.github/actions/setup-elasticsearch
if: ${{ matrix.name == 'search' || matrix.name == 'languages' }}
- uses: ./.github/actions/node-npm-setup
- uses: ./.github/actions/get-docs-early-access
if: ${{ github.repository == 'github/docs-internal' }}
with:
token: ${{ secrets.DOCS_BOT_PAT_BASE }}
- name: Check the test fixture data (if applicable)
if: ${{ matrix.name == 'fixtures' }}
run: npm run copy-fixture-data -- --check
# This keeps our fixture content/data in check
- name: Check the test fixture content (if applicable)
if: ${{ matrix.name == 'fixtures' }}
env:
ROOT: src/fixtures/fixtures
run: |
# If either of these fail, it means our fixture content's internal
# links can and should be updated.
npm run update-internal-links -- --dry-run --check --strict \
src/fixtures/fixtures/content \
--exclude src/fixtures/fixtures/content/get-started/foo/typo-autotitling.md \
--exclude src/fixtures/fixtures/content/get-started/foo/anchor-autotitling.md
npm run update-internal-links -- --dry-run --check --strict \
src/fixtures/fixtures/data
- name: Clone all translations
if: ${{ matrix.name == 'languages' }}
uses: ./.github/actions/clone-translations
with:
token: ${{ secrets.DOCS_BOT_PAT_BASE }}
- name: Gather files changed
if: ${{ matrix.name == 'content-linter' }}
id: changed_files
uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5
- name: Write changed files to diff file
if: ${{ matrix.name == 'content-linter' }}
run: echo "${{ steps.changed_files.outputs.all_modified_files }}" > get_diff_files.txt
- uses: ./.github/actions/cache-nextjs
- name: Run build script
run: npm run build
- uses: ./.github/actions/warmup-remotejson-cache
# Only the 'routing' tests include end-to-end tests about
# archived enterprise server URLs.
if: ${{ matrix.name == 'redirects' }}
- uses: ./.github/actions/precompute-pageinfo
# Only the 'pageinfo' tests include end-to-end tests about this.
if: ${{ matrix.name == 'article-api' }}
env:
ROOT: src/fixtures/fixtures
- name: Index fixtures into the local Elasticsearch
# For the sake of saving time, only run this step if the group
# is one that will run tests against an Elasticsearch on localhost.
if: ${{ matrix.name == 'search' || matrix.name == 'languages' }}
run: npm run index-test-fixtures
- name: Run tests
env:
DIFF_FILE: get_diff_files.txt
CHANGELOG_CACHE_FILE_PATH: src/fixtures/fixtures/changelog-feed.json
# By default, when `process.env.NODE_ENV === 'test'` it forces the
# tests run only in English. The exception is the
# `languages` suite which needs all languages to be set up.
ENABLED_LANGUAGES: ${{ matrix.name == 'languages' && 'all' || '' }}
ROOT: ${{ (matrix.name == 'fixtures' || matrix.name == 'article-api' || matrix.name == 'landings' ) && 'src/fixtures/fixtures' || '' }}
TRANSLATIONS_FIXTURE_ROOT: ${{ (matrix.name == 'fixtures' || matrix.name == 'article-api') && 'src/fixtures/fixtures/translations' || '' }}
# Enable debug logging when "Re-run jobs with debug logging" is used in GitHub Actions UI
# This will output additional timing and path information to help diagnose timeout issues
RUNNER_DEBUG: ${{ runner.debug }}
VITEST_FLAGS: ${{ matrix.name == 'article-api' && '--no-file-parallelism --maxWorkers=1' || '' }}
run: npm test -- $VITEST_FLAGS src/${{ matrix.name }}/tests/

View File

@ -0,0 +1,288 @@
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: jenkins-operator
---
# permissions to do leader election.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: leader-election-role
rules:
- apiGroups:
- ""
- coordination.k8s.io
resources:
- configmaps
- leases
verbs:
- get
- list
- watch
- create
- update
- patch
- delete
- apiGroups:
- ""
resources:
- events
verbs:
- create
- patch
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: jenkins-operator
rules:
- apiGroups:
- apps
resources:
- daemonsets
- deployments
- replicasets
- statefulsets
verbs:
- '*'
- apiGroups:
- apps
- jenkins-operator
resources:
- deployments/finalizers
verbs:
- update
- apiGroups:
- build.openshift.io
resources:
- buildconfigs
- builds
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- configmaps
- secrets
- services
verbs:
- create
- get
- list
- update
- watch
- apiGroups:
- ""
resources:
- events
verbs:
- create
- get
- list
- patch
- watch
- apiGroups:
- ""
resources:
- persistentvolumeclaims
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- pods
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- ""
resources:
- pods
- pods/exec
verbs:
- '*'
- apiGroups:
- ""
resources:
- pods/log
verbs:
- get
- list
- watch
- apiGroups:
- ""
resources:
- pods/portforward
verbs:
- create
- apiGroups:
- ""
resources:
- serviceaccounts
verbs:
- create
- get
- list
- update
- watch
- apiGroups:
- image.openshift.io
resources:
- imagestreams
verbs:
- get
- list
- watch
- apiGroups:
- jenkins.io
resources:
- jenkins/finalizers
verbs:
- update
- apiGroups:
- jenkins.io
resources:
- jenkins/status
verbs:
- get
- patch
- update
- apiGroups:
- jenkins.io
resources:
- '*'
verbs:
- '*'
- apiGroups:
- rbac.authorization.k8s.io
resources:
- rolebindings
- roles
verbs:
- create
- get
- list
- update
- watch
- apiGroups:
- "route.openshift.io"
resources:
- routes
verbs:
- create
- get
- list
- update
- watch
- apiGroups:
- "image.openshift.io"
resources:
- imagestreams
verbs:
- get
- list
- watch
- apiGroups:
- "build.openshift.io"
resources:
- builds
- buildconfigs
verbs:
- get
- list
- watch
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: leader-election-rolebinding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: leader-election-role
subjects:
- kind: ServiceAccount
name: jenkins-operator
---
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: jenkins-operator
subjects:
- kind: ServiceAccount
name: jenkins-operator
roleRef:
kind: Role
name: jenkins-operator
apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: jenkins-operator
labels:
app.kubernetes.io/name: jenkins-operator
helm.sh/chart: jenkins-operator-0.9.0-beta1
app.kubernetes.io/version: "0.9.0-beta1"
spec:
replicas: 1
selector:
matchLabels:
app.kubernetes.io/name: jenkins-operator
template:
metadata:
labels:
app.kubernetes.io/name: jenkins-operator
spec:
serviceAccountName: jenkins-operator
containers:
- name: jenkins-operator
image: quay.io/jenkins-kubernetes-operator/operator:v0.9.0-beta2
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
protocol: TCP
command:
- /manager
args:
livenessProbe:
httpGet:
path: /healthz
port: 8081
initialDelaySeconds: 15
periodSeconds: 20
readinessProbe:
httpGet:
path: /readyz
port: 8081
initialDelaySeconds: 5
periodSeconds: 10
env:
- name: WATCH_NAMESPACE
valueFrom:
fieldRef:
fieldPath: metadata.namespace
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
- name: OPERATOR_NAME
value: "jenkins-operator"
resources:
limits:
cpu: 100m
memory: 120Mi
requests:
cpu: 100m
memory: 120Mi

View File

@ -0,0 +1,19 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
selector:
matchLabels:
app: nginx
replicas: 2 # tells deployment to run 2 pods matching the template
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80

View File

@ -0,0 +1,170 @@
openapi: "3.0.0"
info:
title: Simple API overview
version: 2.0.0
paths:
/:
get:
operationId: listVersionsv2
summary: List API versions
responses:
'200':
description: |-
200 response
content:
application/json:
examples:
foo:
value:
{
"versions": [
{
"status": "CURRENT",
"updated": "2011-01-21T11:33:21Z",
"id": "v2.0",
"links": [
{
"href": "http://127.0.0.1:8774/v2/",
"rel": "self"
}
]
},
{
"status": "EXPERIMENTAL",
"updated": "2013-07-23T11:33:21Z",
"id": "v3.0",
"links": [
{
"href": "http://127.0.0.1:8774/v3/",
"rel": "self"
}
]
}
]
}
'300':
description: |-
300 response
content:
application/json:
examples:
foo:
value: |
{
"versions": [
{
"status": "CURRENT",
"updated": "2011-01-21T11:33:21Z",
"id": "v2.0",
"links": [
{
"href": "http://127.0.0.1:8774/v2/",
"rel": "self"
}
]
},
{
"status": "EXPERIMENTAL",
"updated": "2013-07-23T11:33:21Z",
"id": "v3.0",
"links": [
{
"href": "http://127.0.0.1:8774/v3/",
"rel": "self"
}
]
}
]
}
/v2:
get:
operationId: getVersionDetailsv2
summary: Show API version details
responses:
'200':
description: |-
200 response
content:
application/json:
examples:
foo:
value:
{
"version": {
"status": "CURRENT",
"updated": "2011-01-21T11:33:21Z",
"media-types": [
{
"base": "application/xml",
"type": "application/vnd.openstack.compute+xml;version=2"
},
{
"base": "application/json",
"type": "application/vnd.openstack.compute+json;version=2"
}
],
"id": "v2.0",
"links": [
{
"href": "http://127.0.0.1:8774/v2/",
"rel": "self"
},
{
"href": "http://docs.openstack.org/api/openstack-compute/2/os-compute-devguide-2.pdf",
"type": "application/pdf",
"rel": "describedby"
},
{
"href": "http://docs.openstack.org/api/openstack-compute/2/wadl/os-compute-2.wadl",
"type": "application/vnd.sun.wadl+xml",
"rel": "describedby"
},
{
"href": "http://docs.openstack.org/api/openstack-compute/2/wadl/os-compute-2.wadl",
"type": "application/vnd.sun.wadl+xml",
"rel": "describedby"
}
]
}
}
'203':
description: |-
203 response
content:
application/json:
examples:
foo:
value:
{
"version": {
"status": "CURRENT",
"updated": "2011-01-21T11:33:21Z",
"media-types": [
{
"base": "application/xml",
"type": "application/vnd.openstack.compute+xml;version=2"
},
{
"base": "application/json",
"type": "application/vnd.openstack.compute+json;version=2"
}
],
"id": "v2.0",
"links": [
{
"href": "http://23.253.228.211:8774/v2/",
"rel": "self"
},
{
"href": "http://docs.openstack.org/api/openstack-compute/2/os-compute-devguide-2.pdf",
"type": "application/pdf",
"rel": "describedby"
},
{
"href": "http://docs.openstack.org/api/openstack-compute/2/wadl/os-compute-2.wadl",
"type": "application/vnd.sun.wadl+xml",
"rel": "describedby"
}
]
}
}

View File

@ -0,0 +1,61 @@
openapi: 3.0.0
info:
title: Callback Example
version: 1.0.0
paths:
/streams:
post:
description: subscribes a client to receive out-of-band data
parameters:
- name: callbackUrl
in: query
required: true
description: |
the location where data will be sent. Must be network accessible
by the source server
schema:
type: string
format: uri
example: https://tonys-server.com
responses:
'201':
description: subscription successfully created
content:
application/json:
schema:
description: subscription information
required:
- subscriptionId
properties:
subscriptionId:
description: this unique identifier allows management of the subscription
type: string
example: 2531329f-fb09-4ef7-887e-84e648214436
callbacks:
# the name `onData` is a convenience locator
onData:
# when data is sent, it will be sent to the `callbackUrl` provided
# when making the subscription PLUS the suffix `/data`
'{$request.query.callbackUrl}/data':
post:
requestBody:
description: subscription payload
content:
application/json:
schema:
type: object
properties:
timestamp:
type: string
format: date-time
userData:
type: string
responses:
'202':
description: |
Your server implementation should return this HTTP status code
if the data was received successfully
'204':
description: |
Your server should return this HTTP status code if no longer interested
in further updates

View File

@ -0,0 +1,203 @@
openapi: 3.0.0
info:
title: Link Example
version: 1.0.0
paths:
/2.0/users/{username}:
get:
operationId: getUserByName
parameters:
- name: username
in: path
required: true
schema:
type: string
responses:
'200':
description: The User
content:
application/json:
schema:
$ref: '#/components/schemas/user'
links:
userRepositories:
$ref: '#/components/links/UserRepositories'
/2.0/repositories/{username}:
get:
operationId: getRepositoriesByOwner
parameters:
- name: username
in: path
required: true
schema:
type: string
responses:
'200':
description: repositories owned by the supplied user
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/repository'
links:
userRepository:
$ref: '#/components/links/UserRepository'
/2.0/repositories/{username}/{slug}:
get:
operationId: getRepository
parameters:
- name: username
in: path
required: true
schema:
type: string
- name: slug
in: path
required: true
schema:
type: string
responses:
'200':
description: The repository
content:
application/json:
schema:
$ref: '#/components/schemas/repository'
links:
repositoryPullRequests:
$ref: '#/components/links/RepositoryPullRequests'
/2.0/repositories/{username}/{slug}/pullrequests:
get:
operationId: getPullRequestsByRepository
parameters:
- name: username
in: path
required: true
schema:
type: string
- name: slug
in: path
required: true
schema:
type: string
- name: state
in: query
schema:
type: string
enum:
- open
- merged
- declined
responses:
'200':
description: an array of pull request objects
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/pullrequest'
/2.0/repositories/{username}/{slug}/pullrequests/{pid}:
get:
operationId: getPullRequestsById
parameters:
- name: username
in: path
required: true
schema:
type: string
- name: slug
in: path
required: true
schema:
type: string
- name: pid
in: path
required: true
schema:
type: string
responses:
'200':
description: a pull request object
content:
application/json:
schema:
$ref: '#/components/schemas/pullrequest'
links:
pullRequestMerge:
$ref: '#/components/links/PullRequestMerge'
/2.0/repositories/{username}/{slug}/pullrequests/{pid}/merge:
post:
operationId: mergePullRequest
parameters:
- name: username
in: path
required: true
schema:
type: string
- name: slug
in: path
required: true
schema:
type: string
- name: pid
in: path
required: true
schema:
type: string
responses:
'204':
description: the PR was successfully merged
components:
links:
UserRepositories:
# returns array of '#/components/schemas/repository'
operationId: getRepositoriesByOwner
parameters:
username: $response.body#/username
UserRepository:
# returns '#/components/schemas/repository'
operationId: getRepository
parameters:
username: $response.body#/owner/username
slug: $response.body#/slug
RepositoryPullRequests:
# returns '#/components/schemas/pullrequest'
operationId: getPullRequestsByRepository
parameters:
username: $response.body#/owner/username
slug: $response.body#/slug
PullRequestMerge:
# executes /2.0/repositories/{username}/{slug}/pullrequests/{pid}/merge
operationId: mergePullRequest
parameters:
username: $response.body#/author/username
slug: $response.body#/repository/slug
pid: $response.body#/id
schemas:
user:
type: object
properties:
username:
type: string
uuid:
type: string
repository:
type: object
properties:
slug:
type: string
owner:
$ref: '#/components/schemas/user'
pullrequest:
type: object
properties:
id:
type: integer
title:
type: string
repository:
$ref: '#/components/schemas/repository'
author:
$ref: '#/components/schemas/user'

View File

@ -0,0 +1,158 @@
openapi: "3.0.0"
info:
version: 1.0.0
title: Swagger Petstore
description: A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.0 specification
termsOfService: http://swagger.io/terms/
contact:
name: Swagger API Team
email: apiteam@swagger.io
url: http://swagger.io
license:
name: Apache 2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
servers:
- url: https://petstore.swagger.io/v2
paths:
/pets:
get:
description: |
Returns all pets from the system that the user has access to
Nam sed condimentum est. Maecenas tempor sagittis sapien, nec rhoncus sem sagittis sit amet. Aenean at gravida augue, ac iaculis sem. Curabitur odio lorem, ornare eget elementum nec, cursus id lectus. Duis mi turpis, pulvinar ac eros ac, tincidunt varius justo. In hac habitasse platea dictumst. Integer at adipiscing ante, a sagittis ligula. Aenean pharetra tempor ante molestie imperdiet. Vivamus id aliquam diam. Cras quis velit non tortor eleifend sagittis. Praesent at enim pharetra urna volutpat venenatis eget eget mauris. In eleifend fermentum facilisis. Praesent enim enim, gravida ac sodales sed, placerat id erat. Suspendisse lacus dolor, consectetur non augue vel, vehicula interdum libero. Morbi euismod sagittis libero sed lacinia.
Sed tempus felis lobortis leo pulvinar rutrum. Nam mattis velit nisl, eu condimentum ligula luctus nec. Phasellus semper velit eget aliquet faucibus. In a mattis elit. Phasellus vel urna viverra, condimentum lorem id, rhoncus nibh. Ut pellentesque posuere elementum. Sed a varius odio. Morbi rhoncus ligula libero, vel eleifend nunc tristique vitae. Fusce et sem dui. Aenean nec scelerisque tortor. Fusce malesuada accumsan magna vel tempus. Quisque mollis felis eu dolor tristique, sit amet auctor felis gravida. Sed libero lorem, molestie sed nisl in, accumsan tempor nisi. Fusce sollicitudin massa ut lacinia mattis. Sed vel eleifend lorem. Pellentesque vitae felis pretium, pulvinar elit eu, euismod sapien.
operationId: findPets
parameters:
- name: tags
in: query
description: tags to filter by
required: false
style: form
schema:
type: array
items:
type: string
- name: limit
in: query
description: maximum number of results to return
required: false
schema:
type: integer
format: int32
responses:
'200':
description: pet response
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Pet'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
post:
description: Creates a new pet in the store. Duplicates are allowed
operationId: addPet
requestBody:
description: Pet to add to the store
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/NewPet'
responses:
'200':
description: pet response
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
/pets/{id}:
get:
description: Returns a user based on a single ID, if the user does not have access to the pet
operationId: find pet by id
parameters:
- name: id
in: path
description: ID of pet to fetch
required: true
schema:
type: integer
format: int64
responses:
'200':
description: pet response
content:
application/json:
schema:
$ref: '#/components/schemas/Pet'
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
delete:
description: deletes a single pet based on the ID supplied
operationId: deletePet
parameters:
- name: id
in: path
description: ID of pet to delete
required: true
schema:
type: integer
format: int64
responses:
'204':
description: pet deleted
default:
description: unexpected error
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
components:
schemas:
Pet:
allOf:
- $ref: '#/components/schemas/NewPet'
- type: object
required:
- id
properties:
id:
type: integer
format: int64
NewPet:
type: object
required:
- name
properties:
name:
type: string
tag:
type: string
Error:
type: object
required:
- code
- message
properties:
code:
type: integer
format: int32
message:
type: string

View File

@ -0,0 +1,210 @@
openapi: 3.0.1
servers:
- url: '{scheme}://developer.uspto.gov/ds-api'
variables:
scheme:
description: 'The Data Set API is accessible via https and http'
enum:
- 'https'
- 'http'
default: 'https'
info:
description: >-
The Data Set API (DSAPI) allows the public users to discover and search
USPTO exported data sets. This is a generic API that allows USPTO users to
make any CSV based data files searchable through API. With the help of GET
call, it returns the list of data fields that are searchable. With the help
of POST call, data can be fetched based on the filters on the field names.
Please note that POST call is used to search the actual data. The reason for
the POST call is that it allows users to specify any complex search criteria
without worry about the GET size limitations as well as encoding of the
input parameters.
version: 1.0.0
title: USPTO Data Set API
contact:
name: Open Data Portal
url: 'https://developer.uspto.gov'
email: developer@uspto.gov
tags:
- name: metadata
description: Find out about the data sets
- name: search
description: Search a data set
paths:
/:
get:
tags:
- metadata
operationId: list-data-sets
summary: List available data sets
responses:
'200':
description: Returns a list of data sets
content:
application/json:
schema:
$ref: '#/components/schemas/dataSetList'
example:
{
"total": 2,
"apis": [
{
"apiKey": "oa_citations",
"apiVersionNumber": "v1",
"apiUrl": "https://developer.uspto.gov/ds-api/oa_citations/v1/fields",
"apiDocumentationUrl": "https://developer.uspto.gov/ds-api-docs/index.html?url=https://developer.uspto.gov/ds-api/swagger/docs/oa_citations.json"
},
{
"apiKey": "cancer_moonshot",
"apiVersionNumber": "v1",
"apiUrl": "https://developer.uspto.gov/ds-api/cancer_moonshot/v1/fields",
"apiDocumentationUrl": "https://developer.uspto.gov/ds-api-docs/index.html?url=https://developer.uspto.gov/ds-api/swagger/docs/cancer_moonshot.json"
}
]
}
/{dataset}/{version}/fields:
get:
tags:
- metadata
summary: >-
Provides the general information about the API and the list of fields
that can be used to query the dataset.
description: >-
This GET API returns the list of all the searchable field names that are
in the oa_citations. Please see the 'fields' attribute which returns an
array of field names. Each field or a combination of fields can be
searched using the syntax options shown below.
operationId: list-searchable-fields
parameters:
- name: dataset
in: path
description: 'Name of the dataset.'
required: true
example: "oa_citations"
schema:
type: string
- name: version
in: path
description: Version of the dataset.
required: true
example: "v1"
schema:
type: string
responses:
'200':
description: >-
The dataset API for the given version is found and it is accessible
to consume.
content:
application/json:
schema:
type: string
'404':
description: >-
The combination of dataset name and version is not found in the
system or it is not published yet to be consumed by public.
content:
application/json:
schema:
type: string
/{dataset}/{version}/records:
post:
tags:
- search
summary: >-
Provides search capability for the data set with the given search
criteria.
description: >-
This API is based on Solr/Lucene Search. The data is indexed using
SOLR. This GET API returns the list of all the searchable field names
that are in the Solr Index. Please see the 'fields' attribute which
returns an array of field names. Each field or a combination of fields
can be searched using the Solr/Lucene Syntax. Please refer
https://lucene.apache.org/core/3_6_2/queryparsersyntax.html#Overview for
the query syntax. List of field names that are searchable can be
determined using above GET api.
operationId: perform-search
parameters:
- name: version
in: path
description: Version of the dataset.
required: true
schema:
type: string
default: v1
- name: dataset
in: path
description: 'Name of the dataset. In this case, the default value is oa_citations'
required: true
schema:
type: string
default: oa_citations
responses:
'200':
description: successful operation
content:
application/json:
schema:
type: array
items:
type: object
additionalProperties:
type: object
'404':
description: No matching record found for the given criteria.
requestBody:
content:
application/x-www-form-urlencoded:
schema:
type: object
properties:
criteria:
description: >-
Uses Lucene Query Syntax in the format of
propertyName:value, propertyName:[num1 TO num2] and date
range format: propertyName:[yyyyMMdd TO yyyyMMdd]. In the
response please see the 'docs' element which has the list of
record objects. Each record structure would consist of all
the fields and their corresponding values.
type: string
default: '*:*'
start:
description: Starting record number. Default value is 0.
type: integer
default: 0
rows:
description: >-
Specify number of rows to be returned. If you run the search
with default values, in the response you will see 'numFound'
attribute which will tell the number of records available in
the dataset.
type: integer
default: 100
required:
- criteria
components:
schemas:
dataSetList:
type: object
properties:
total:
type: integer
apis:
type: array
items:
type: object
properties:
apiKey:
type: string
description: To be used as a dataset parameter value
apiVersionNumber:
type: string
description: To be used as a version parameter value
apiUrl:
type: string
format: uriref
description: "The URL describing the dataset's fields"
apiDocumentationUrl:
type: string
format: uriref
description: A URL to the API console for each API

View File

@ -0,0 +1,24 @@
name: Ada (GNAT)
on:
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up GNAT toolchain
run: >
sudo apt-get update &&
sudo apt-get install gnat gprbuild
- name: Build
run: gprbuild -j0 -p

View File

@ -0,0 +1,26 @@
name: Android CI
on:
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: set up JDK 11
uses: actions/setup-java@v4
with:
java-version: '11'
distribution: 'temurin'
cache: gradle
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build

View File

@ -0,0 +1,25 @@
# This workflow will build a Java project with Ant
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-java-with-ant
name: Java CI
on:
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up JDK 11
uses: actions/setup-java@v4
with:
java-version: '11'
distribution: 'temurin'
- name: Build with Ant
run: ant -noinput -buildfile build.xml

View File

@ -0,0 +1,36 @@
# This is a basic workflow to help you get started with Actions
name: CI
# Controls when the workflow will run
on:
# Triggers the workflow on push or pull request events but only for the $default-branch branch
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
# This workflow contains a single job called "build"
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v4
# Runs a single command using the runners shell
- name: Run a one-line script
run: echo Hello, world!
# Runs a set of commands using the runners shell
- name: Run a multi-line script
run: |
echo Add other actions to build,
echo test, and deploy your project.

View File

@ -0,0 +1,23 @@
name: C/C++ CI
on:
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: configure
run: ./configure
- name: make
run: make
- name: make check
run: make check
- name: make distcheck
run: make distcheck

View File

@ -0,0 +1,19 @@
name: Clojure CI
on:
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: lein deps
- name: Run tests
run: lein test

View File

@ -0,0 +1,75 @@
# This starter workflow is for a CMake project running on multiple platforms. There is a different starter workflow if you just want a single platform.
# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-single-platform.yml
name: CMake on multiple platforms
on:
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
# Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable.
fail-fast: false
# Set up a matrix to run the following 3 configurations:
# 1. <Windows, Release, latest MSVC compiler toolchain on the default runner image, default generator>
# 2. <Linux, Release, latest GCC compiler toolchain on the default runner image, default generator>
# 3. <Linux, Release, latest Clang compiler toolchain on the default runner image, default generator>
#
# To add more build types (Release, Debug, RelWithDebInfo, etc.) customize the build_type list.
matrix:
os: [ubuntu-latest, windows-latest]
build_type: [Release]
c_compiler: [gcc, clang, cl]
include:
- os: windows-latest
c_compiler: cl
cpp_compiler: cl
- os: ubuntu-latest
c_compiler: gcc
cpp_compiler: g++
- os: ubuntu-latest
c_compiler: clang
cpp_compiler: clang++
exclude:
- os: windows-latest
c_compiler: gcc
- os: windows-latest
c_compiler: clang
- os: ubuntu-latest
c_compiler: cl
steps:
- uses: actions/checkout@v4
- name: Set reusable strings
# Turn repeated input strings (such as the build output directory) into step outputs. These step outputs can be used throughout the workflow file.
id: strings
shell: bash
run: |
echo "build-output-dir=${{ github.workspace }}/build" >> "$GITHUB_OUTPUT"
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: >
cmake -B ${{ steps.strings.outputs.build-output-dir }}
-DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }}
-DCMAKE_C_COMPILER=${{ matrix.c_compiler }}
-DCMAKE_BUILD_TYPE=${{ matrix.build_type }}
-S ${{ github.workspace }}
- name: Build
# Build your program with the given configuration. Note that --config is needed because the default Windows generator is a multi-config generator (Visual Studio generator).
run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }}
- name: Test
working-directory: ${{ steps.strings.outputs.build-output-dir }}
# Execute tests defined by the CMake configuration. Note that --build-config is needed because the default Windows generator is a multi-config generator (Visual Studio generator).
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: ctest --build-config ${{ matrix.build_type }}

View File

@ -0,0 +1,39 @@
# This starter workflow is for a CMake project running on a single platform. There is a different starter workflow if you need cross-platform coverage.
# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-multi-platform.yml
name: CMake on a single platform
on:
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release
jobs:
build:
# The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
# You can convert this to a matrix build if you need cross-platform coverage.
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
- name: Build
# Build your program with the given configuration
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
- name: Test
working-directory: ${{github.workspace}}/build
# Execute tests defined by the CMake configuration.
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: ctest -C ${{env.BUILD_TYPE}}

View File

@ -0,0 +1,22 @@
name: Crystal CI
on:
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]
jobs:
build:
runs-on: ubuntu-latest
container:
image: crystallang/crystal
steps:
- uses: actions/checkout@v4
- name: Install dependencies
run: shards install
- name: Run tests
run: crystal spec

View File

@ -0,0 +1,32 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
name: D
on:
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: dlang-community/setup-dlang@4c99aa991ce7d19dd3064de0a4f2f6b2f152e2d7
- name: 'Build & Test'
run: |
# Build the project, with its main file included, without unittests
dub build --compiler=$DC
# Build and run tests, as defined by `unittest` configuration
# In this mode, `mainSourceFile` is excluded and `version (unittest)` are included
# See https://dub.pm/package-format-json.html#configurations
dub test --compiler=$DC

View File

@ -0,0 +1,42 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
name: Dart
on:
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Note: This workflow uses the latest stable version of the Dart SDK.
# You can specify other versions if desired, see documentation here:
# https://github.com/dart-lang/setup-dart/blob/main/README.md
# - uses: dart-lang/setup-dart@v1
- uses: dart-lang/setup-dart@9a04e6d73cca37bd455e0608d7e5092f881fd603
- name: Install dependencies
run: dart pub get
# Uncomment this step to verify the use of 'dart format' on each commit.
# - name: Verify formatting
# run: dart format --output=none --set-exit-if-changed .
# Consider passing '--fatal-infos' for slightly stricter analysis.
- name: Analyze project source
run: dart analyze
# Your project will need to have tests in test/ and a dependency on
# package:test for this step to succeed. Note that Flutter projects will
# want to change this to 'flutter test'.
- name: Run tests
run: dart test

View File

@ -0,0 +1,38 @@
# This workflow will trigger Datadog Synthetic tests within your Datadog organisation
# For more information on running Synthetic tests within your GitHub workflows see: https://docs.datadoghq.com/synthetics/cicd_integrations/github_actions/
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# To get started:
# 1. Add your Datadog API (DD_API_KEY) and Application Key (DD_APP_KEY) as secrets to your GitHub repository. For more information, see: https://docs.datadoghq.com/account_management/api-app-keys/.
# 2. Start using the action within your workflow
name: Run Datadog Synthetic tests
on:
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Run Synthetic tests within your GitHub workflow.
# For additional configuration options visit the action within the marketplace: https://github.com/marketplace/actions/datadog-synthetics-ci
- name: Run Datadog Synthetic tests
uses: DataDog/synthetics-ci-github-action@87b505388a22005bb8013481e3f73a367b9a53eb # v1.4.0
with:
api_key: ${{secrets.DD_API_KEY}}
app_key: ${{secrets.DD_APP_KEY}}
test_search_query: 'tag:e2e-tests' #Modify this tag to suit your tagging strategy

View File

@ -0,0 +1,42 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will install Deno then run `deno lint` and `deno test`.
# For more information see: https://github.com/denoland/setup-deno
name: Deno
on:
push:
branches: [$default-branch]
pull_request:
branches: [$default-branch]
permissions:
contents: read
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Setup repo
uses: actions/checkout@v4
- name: Setup Deno
# uses: denoland/setup-deno@v1
uses: denoland/setup-deno@61fe2df320078202e33d7d5ad347e7dcfa0e8f31 # v1.1.2
with:
deno-version: v1.x
# Uncomment this step to verify the use of 'deno fmt' on each commit.
# - name: Verify formatting
# run: deno fmt --check
- name: Run linter
run: deno lint
- name: Run tests
run: deno test -A

View File

@ -0,0 +1,30 @@
name: Django CI
on:
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]
jobs:
build:
runs-on: ubuntu-latest
strategy:
max-parallel: 4
matrix:
python-version: [3.7, 3.8, 3.9]
steps:
- uses: actions/checkout@v4
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v3
with:
python-version: ${{ matrix.python-version }}
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
- name: Run Tests
run: |
python manage.py test

View File

@ -0,0 +1,18 @@
name: Docker Image CI
on:
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build the Docker image
run: docker build . --file Dockerfile --tag my-image-name:$(date +%s)

View File

@ -0,0 +1,98 @@
name: Docker
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
on:
schedule:
- cron: $cron-daily
push:
branches: [ $default-branch ]
# Publish semver tags as releases.
tags: [ 'v*.*.*' ]
pull_request:
branches: [ $default-branch ]
env:
# Use docker.io for Docker Hub if empty
REGISTRY: ghcr.io
# github.repository as <account>/<repo>
IMAGE_NAME: ${{ github.repository }}
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
# This is used to complete the identity challenge
# with sigstore/fulcio when running outside of PRs.
id-token: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Install the cosign tool except on PR
# https://github.com/sigstore/cosign-installer
- name: Install cosign
if: github.event_name != 'pull_request'
uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 #v3.5.0
with:
cosign-release: 'v2.2.4'
# Set up BuildKit Docker container builder to be able to build
# multi-platform images and export cache
# https://github.com/docker/setup-buildx-action
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
# Login against a Docker registry except on PR
# https://github.com/docker/login-action
- name: Log into registry ${{ env.REGISTRY }}
if: github.event_name != 'pull_request'
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# Extract metadata (tags, labels) for Docker
# https://github.com/docker/metadata-action
- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# Build and push Docker image with Buildx (don't push on PR)
# https://github.com/docker/build-push-action
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Sign the resulting Docker image digest except on PRs.
# This will only write to the public Rekor transparency log when the Docker
# repository is public to avoid leaking data. If you would like to publish
# transparency data even for private images, pass --force to cosign below.
# https://github.com/sigstore/cosign
- name: Sign the published Docker image
if: ${{ github.event_name != 'pull_request' }}
env:
# https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions#using-an-intermediate-environment-variable
TAGS: ${{ steps.meta.outputs.tags }}
DIGEST: ${{ steps.build-and-push.outputs.digest }}
# This step uses the identity token to provision an ephemeral certificate
# against the sigstore community Fulcio instance.
run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST}

View File

@ -0,0 +1,115 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will build, test, sign and package a WPF or Windows Forms desktop application
# built on .NET Core.
# To learn how to migrate your existing application to .NET Core,
# refer to https://docs.microsoft.com/en-us/dotnet/desktop-wpf/migration/convert-project-from-net-framework
#
# To configure this workflow:
#
# 1. Configure environment variables
# GitHub sets default environment variables for every workflow run.
# Replace the variables relative to your project in the "env" section below.
#
# 2. Signing
# Generate a signing certificate in the Windows Application
# Packaging Project or add an existing signing certificate to the project.
# Next, use PowerShell to encode the .pfx file using Base64 encoding
# by running the following Powershell script to generate the output string:
#
# $pfx_cert = Get-Content '.\SigningCertificate.pfx' -Encoding Byte
# [System.Convert]::ToBase64String($pfx_cert) | Out-File 'SigningCertificate_Encoded.txt'
#
# Open the output file, SigningCertificate_Encoded.txt, and copy the
# string inside. Then, add the string to the repo as a GitHub secret
# and name it "Base64_Encoded_Pfx."
# For more information on how to configure your signing certificate for
# this workflow, refer to https://github.com/microsoft/github-actions-for-desktop-apps#signing
#
# Finally, add the signing certificate password to the repo as a secret and name it "Pfx_Key".
# See "Build the Windows Application Packaging project" below to see how the secret is used.
#
# For more information on GitHub Actions, refer to https://github.com/features/actions
# For a complete CI/CD sample to get started with GitHub Action workflows for Desktop Applications,
# refer to https://github.com/microsoft/github-actions-for-desktop-apps
name: .NET Core Desktop
on:
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]
jobs:
build:
strategy:
matrix:
configuration: [Debug, Release]
runs-on: windows-latest # For a list of available runner types, refer to
# https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on
env:
Solution_Name: your-solution-name # Replace with your solution name, i.e. MyWpfApp.sln.
Test_Project_Path: your-test-project-path # Replace with the path to your test project, i.e. MyWpfApp.Tests\MyWpfApp.Tests.csproj.
Wap_Project_Directory: your-wap-project-directory-name # Replace with the Wap project directory relative to the solution, i.e. MyWpfApp.Package.
Wap_Project_Path: your-wap-project-path # Replace with the path to your Wap project, i.e. MyWpf.App.Package\MyWpfApp.Package.wapproj.
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
# Install the .NET Core workload
- name: Install .NET Core
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
# Add MSBuild to the PATH: https://github.com/microsoft/setup-msbuild
- name: Setup MSBuild.exe
uses: microsoft/setup-msbuild@v2
# Execute all unit tests in the solution
- name: Execute unit tests
run: dotnet test
# Restore the application to populate the obj folder with RuntimeIdentifiers
- name: Restore the application
run: msbuild $env:Solution_Name /t:Restore /p:Configuration=$env:Configuration
env:
Configuration: ${{ matrix.configuration }}
# Decode the base 64 encoded pfx and save the Signing_Certificate
- name: Decode the pfx
run: |
$pfx_cert_byte = [System.Convert]::FromBase64String("${{ secrets.Base64_Encoded_Pfx }}")
$certificatePath = Join-Path -Path $env:Wap_Project_Directory -ChildPath GitHubActionsWorkflow.pfx
[IO.File]::WriteAllBytes("$certificatePath", $pfx_cert_byte)
# Create the app package by building and packaging the Windows Application Packaging project
- name: Create the app package
run: msbuild $env:Wap_Project_Path /p:Configuration=$env:Configuration /p:UapAppxPackageBuildMode=$env:Appx_Package_Build_Mode /p:AppxBundle=$env:Appx_Bundle /p:PackageCertificateKeyFile=GitHubActionsWorkflow.pfx /p:PackageCertificatePassword=${{ secrets.Pfx_Key }}
env:
Appx_Bundle: Always
Appx_Bundle_Platforms: x86|x64
Appx_Package_Build_Mode: StoreUpload
Configuration: ${{ matrix.configuration }}
# Remove the pfx
- name: Remove the pfx
run: Remove-Item -path $env:Wap_Project_Directory\GitHubActionsWorkflow.pfx
# Upload the MSIX package: https://github.com/marketplace/actions/upload-a-build-artifact
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: MSIX Package
path: ${{ env.Wap_Project_Directory }}\AppPackages

View File

@ -0,0 +1,28 @@
# This workflow will build a .NET project
# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
name: .NET
on:
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: 8.0.x
- name: Restore dependencies
run: dotnet restore
- name: Build
run: dotnet build --no-restore
- name: Test
run: dotnet test --no-build --verbosity normal

View File

@ -0,0 +1,39 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
name: Elixir CI
on:
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]
permissions:
contents: read
jobs:
build:
name: Build and test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Elixir
uses: erlef/setup-beam@61e01a43a562a89bfc54c7f9a378ff67b03e4a21 # v1.16.0
with:
elixir-version: '1.15.2' # [Required] Define the Elixir version
otp-version: '26.0' # [Required] Define the Erlang/OTP version
- name: Restore dependencies cache
uses: actions/cache@v3
with:
path: deps
key: ${{ runner.os }}-mix-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ runner.os }}-mix-
- name: Install dependencies
run: mix deps.get
- name: Run tests
run: mix test

View File

@ -0,0 +1,26 @@
name: Erlang CI
on:
push:
branches: [ $default-branch ]
pull_request:
branches: [ $default-branch ]
permissions:
contents: read
jobs:
build:
runs-on: ubuntu-latest
container:
image: erlang:22.0.7
steps:
- uses: actions/checkout@v4
- name: Compile
run: rebar3 compile
- name: Run tests
run: rebar3 do eunit, ct

View File

@ -0,0 +1,19 @@
apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
name: "deploy-replica-policy.example.com"
spec:
paramKind:
apiVersion: rules.example.com/v1
kind: ReplicaLimit
matchConstraints:
resourceRules:
- apiGroups: ["apps"]
apiVersions: ["v1"]
operations: ["CREATE", "UPDATE"]
resources: ["deployments"]
validations:
- expression: "object.spec.replicas <= params.maxReplicas"
messageExpression: "'object.spec.replicas must be no greater than ' + string(params.maxReplicas)"
reason: Invalid

Some files were not shown because too many files have changed in this diff Show More