From 6e699be956af35fff0c4b822e7ffc22f5f8c9044 Mon Sep 17 00:00:00 2001 From: Eivind Grimstad Date: Wed, 30 Sep 2026 10:23:23 +0200 Subject: [PATCH] wip --- .github/README.md | 6 +- .github/workflows/cd.yml | 2 + .github/workflows/upload.yml | 171 +++++++++++++++++++++++++++++++++++ README-upload.md | 65 +++++++++++++ 4 files changed, 240 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/upload.yml create mode 100644 README-upload.md diff --git a/.github/README.md b/.github/README.md index d2fab70..4be1b2e 100644 --- a/.github/README.md +++ b/.github/README.md @@ -1,15 +1,13 @@

entur/gha-api

[![Entur/API/CI](https://github.com/entur/gha-api/actions/workflows/ci.yml/badge.svg)](https://github.com/entur/gha-api/actions/workflows/ci.yml) -[![Lint OpenAPI specs](https://github.com/entur/gha-api/actions/workflows/lint.yml/badge.svg)](https://github.com/entur/gha-api/actions/workflows/lint.yml) -[![Publish OpenAPI specs](https://github.com/entur/gha-api/actions/workflows/publish.yml/badge.svg)](https://github.com/entur/gha-api/actions/workflows/publish.yml) [![License](https://img.shields.io/github/license/entur/gha-api)](https://github.com/entur/gha-api) Github reusable workflows to help Entur teams: - [Lint OpenAPI specs](../README-lint.md) - [Validate OpenAPI specs](../README-validate.md) -- [Publish OpenAPI specs to the developer portal](../README-publish.md) +- [Upload OpenAPI specs and publish to the developer portal](../README-upload.md) ## Golden Path @@ -66,7 +64,7 @@ jobs: with: environment: prd - openapi-publish: + openapi-upload: needs: helm-deploy # Publish specification after deployment to production has suceeded uses: entur/gha-api/.github/workflows/publish.yml@v6 secrets: inherit diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index fbcb21f..2843e27 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -29,6 +29,8 @@ jobs: readme: README-validate.md - workflow: .github/workflows/publish.yml readme: README-publish.md + - workflow: .github/workflows/upload.yml + readme: README-upload.md uses: entur/gha-meta/.github/workflows/auto-doc.yml@v1 with: commit_default_author: 'github_actions' diff --git a/.github/workflows/upload.yml b/.github/workflows/upload.yml new file mode 100644 index 0000000..80b87cf --- /dev/null +++ b/.github/workflows/upload.yml @@ -0,0 +1,171 @@ +name: Entur/API/Upload + +on: + workflow_call: + inputs: + path: + description: "Path to OpenAPI specification" + type: string + artifact: + description: "Artifact containing the OpenAPI specification." + type: string + environment: + description: "The environment to operate against. dev|prd. Default: prd" + type: string + default: prd + release: + description: "If true, the specification will be released to the developer portal. If false, it will only be uploaded as a draft." + type: boolean + required: true + +jobs: + upload: + name: OpenAPI Upload + runs-on: ubuntu-26.04 + permissions: + contents: read + actions: read + id-token: write + env: + GHA_API_ARTIFACT: ${{ inputs.artifact }} + GHA_API_PATH: ${{ inputs.path }} + GHA_API_ENV: ${{ inputs.env }} + GHA_API_CLOUD_RUN_ENDPOINT: https://europe-west1-ent-apidata-${{ inputs.env }}.cloudfunctions.net/publish-spec + steps: + - name: Checkout repository (if spec provided) + if: ${{ inputs.artifact == '' }} + uses: actions/checkout@v7 + - name: Download artifact (if artifact provided) + if: ${{ inputs.artifact != '' }} + uses: actions/download-artifact@v8 + with: + pattern: ${{ inputs.artifact }} + path: /tmp/artifacts + - name: Validate inputs + run: | + # Print every statement if debugging + [ -n "${{ runner.debug }}" ] && set -x + set -euo pipefail + + # Validate fail_threshold + case "$GHA_API_ENV" in + dev|prd) + ;; # OK + *) + echo "::error::env must be one of: dev, prd" + exit 1 + ;; + esac + - name: Resolve spec path + id: resolve-spec-path + run: | + # Resolve spec path based on inputs + if [ -n "$GHA_API_ARTIFACT" ]; then + if [ -n "$GHA_API_PATH" ]; then + spec_path="/tmp/artifacts/$GHA_API_PATH" + else + spec_path="/tmp/artifacts/openapi.yaml" + fi + else + if [ -n "$GHA_API_PATH" ]; then + spec_path="$GHA_API_PATH" + else + spec_path="specs/openapi.yaml" + fi + fi + + echo "Path to spec resolved to $spec_path" + + if [ ! -f $spec_path ]; then + echo "File $spec_path not found." + exit 1 + fi + + echo "spec_path=$spec_path" >> "$GITHUB_OUTPUT" + - name: Checkout linting rulesets + uses: actions/checkout@v7 + with: + repository: entur/api-guidelines + ref: v3.4.0 + path: rulesets + sparse-checkout-cone-mode: false + sparse-checkout: | + .spectral-required.yml + functions/*.js + - uses: $/.github/actions/setup-spectral + name: Setup spectral + - uses: $/.github/actions/setup-redocly + name: Setup redocly + - name: Validate spec + shell: bash + env: + GHA_API_PATH: ${{ steps.resolve-spec-path.outputs.spec_path }} + run: | + set -o errexit + set -o nounset + set -o pipefail + shopt -s globstar + + if ! spectral lint "$GHA_API_PATH" --ruleset "rulesets/.spectral-required.yml"; then + echo "::error::Spec validation failed. Failing workflow." + exit 1 + fi + + if ! redocly bundle $GHA_API_PATH; then + echo "::error::Spec bundling failed. Failing workflow." + exit 1 + fi + - name: Authenticate with Google Cloud + id: auth + uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 + with: + workload_identity_provider: ${{ vars.CI_WORKLOAD_IDENTITY_PROVIDER }} + service_account: ${{ vars.CI_SERVICE_ACCOUNT }} + token_format: id_token + id_token_audience: ${{ env.GHA_API_CLOUD_RUN_ENDPOINT }} + id_token_include_email: true + create_credentials_file: false + - name: Upload + env: + GHA_API_PATH: ${{ steps.resolve-spec-path.outputs.spec_path }} + GHA_API_RELEASE: ${{ inputs.release }} + ID_TOKEN: ${{ steps.auth.outputs.id_token }} + shell: bash + run: | + set -o errexit + set -o nounset + set -o pipefail + shopt -s globstar + + filename=$(basename $GHA_API_PATH) + mkdir -p /tmp/specs + redocly bundle -o /tmp/specs/$filename $GHA_API_PATH + + # Extract repository name (without owner) + REPO_NAME="${GITHUB_REPOSITORY#*/}" + + # Create metadata JSON + METADATA="{\"repository\": \"$REPO_NAME\", \"github\": { \"sha\": \"$GITHUB_SHA\", \"ref\": \"$GITHUB_REF\", \"runId\": \"$GITHUB_RUN_ID\" }}" + + echo "Uploading spec: $GHA_API_PATH" + + RESPONSE=$(curl --fail-with-body -sS \ + -X PUT \ + -H "Authorization: Bearer $ID_TOKEN" \ + -F "metadata=$METADATA;type=application/json" \ + -F "spec=@/tmp/specs/$filename" \ + "$GHA_API_CLOUD_RUN_ENDPOINT?release=$GHA_API_RELEASE") || { + DETAIL=$(echo "$RESPONSE" | jq -r '.detail') + echo "::error file=$GHA_API_PATH,line=1::$DETAIL" + exit 1 + } + + echo "Successfully uploaded: $GHA_API_PATH" + - name: Send analytics + if: always() + uses: $/.github/actions/posthog + with: + workflow_name: upload + workflow_inputs: ${{ toJSON(inputs) }} + api_key: "phc_yhR5iXxjC2n6J7tqznFQURld147kruAy4HuYgjbyEyk" + diff --git a/README-upload.md b/README-upload.md new file mode 100644 index 0000000..3e1ccac --- /dev/null +++ b/README-upload.md @@ -0,0 +1,65 @@ +# `gha-api/upload` + +Upload an OpenAPI specification to Enturs central registry, publishing it to [Enturs developer documentation](https://beta.developer.entur.no). + + +> [!TIP] +> `gha-api/upload` is usually called in your deployment workflow. If you want to validate that `gha-api/upload` will work before you merge a pull request, use [`gha-api/validate`](README-validate.md) in your integration workflow. +## Inputs + + + +| INPUT | TYPE | REQUIRED | DEFAULT | DESCRIPTION | +|----------------------------------------------------------|--------|----------|---------|----------------------------------------------------------------| +| [artifact](#input_artifact) | string | false | | Artifact containing the OpenAPI specification. | +| [env](#input_env) | string | false | `"prd"` | The environment to operate against.
dev|prd. Default: prd | +| [path](#input_path) | string | false | | Path to OpenAPI specification | + + + +## Outputs + + +No outputs. + + +# Usage +Add the following step to your workflow configuration. +By default, the workflow looks for a specification at `specs/openapi.yaml`. + +```yml +#cd.yml + +jobs: + openapi-upload: + uses: entur/gha-api/.github/workflows/upload.yml@v6 + secrets: inherit +``` + +## Specifying path to spec +If your spec is in another file, you can specify it using the `path` input. + +```yml +#cd.yml + +jobs: + openapi-upload: + uses: entur/gha-api/.github/workflows/upload.yml@v6 + with: + path: specs/openapi.json + secrets: inherit +``` + +## Using a generated spec + +If your spec is generated as part of your workflow, you can specify the artifact name using the `artifact` input. +When `artifact` is specified, `path` should refer to a file inside the artifact, by default `openapi.yaml`. + +```yml +#cd.yml +jobs: + openapi-upload: + uses: entur/gha-api/.github/workflows/upload.yml@v6 + with: + artifact: myArtifactName +```