diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 0000000..3f822d6 --- /dev/null +++ b/.github/workflows/test.yaml @@ -0,0 +1,40 @@ +name: 'Test OpenAPI Spec Diff Action' +on: push +jobs: + oas_diff_job: + runs-on: ubuntu-latest + name: A job to test OpenAPI Spec diff action + steps: + - name: checkout + uses: actions/checkout@v3 + - name: Running OpenAPI Spec diff action + id: test_ete + uses: ./diff + with: + base: 'specs/base.yaml' + revision: 'specs/revision.yaml' + format: 'text' + oas_diff_breaking_changes_job: + runs-on: ubuntu-latest + name: A job to test OpenAPI Spec breaking changes + steps: + - name: checkout + uses: actions/checkout@v3 + - name: Running OpenAPI Spec check breaking action + id: test_breaking_changes + uses: ./check-breaking + with: + base: https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml + revision: https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml + oas_diff_breaking_changes_latest_job: + runs-on: ubuntu-latest + name: A job to test latest release of OpenAPI Spec breaking changes action + steps: + - name: checkout + uses: actions/checkout@v3 + - name: Running OpenAPI Spec check breaking latest action + id: test_breaking_changes + uses: oasdiff/oasdiff-action/check-breaking@latest + with: + base: https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml + revision: https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml diff --git a/.gitignore b/.gitignore index 3b735ec..1c2d52b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,21 +1 @@ -# If you prefer the allow list template instead of the deny list, see community template: -# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore -# -# Binaries for programs and plugins -*.exe -*.exe~ -*.dll -*.so -*.dylib - -# Test binary, built with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Dependency directories (remove the comment below to include it) -# vendor/ - -# Go workspace file -go.work +.idea/* diff --git a/README.md b/README.md index b84541d..4acd8f3 100644 --- a/README.md +++ b/README.md @@ -1 +1,32 @@ -# oasdiff-action \ No newline at end of file +# oasdiff-action +[![CI](https://github.com/oasdiff/oasdiff-action/actions/workflows/test.yaml/badge.svg)](https://github.com/oasdiff/oasdiff-action/actions) + +GitHub actions for comparing OpenAPI specs and detect breaking changes, based on [oasdiff](https://github.com/Tufin/oasdiff) tool + +## How to use? +Depend on your use case: + +### Find diff +Copy and paste the following snippet into your build .yml file: +``` +- name: Running OpenAPI Spec diff action + id: test_ete + uses: oasdiff/oasdiff-action/diff@latest + with: + base: 'specs/base.yaml' + revision: 'specs/revision.yaml' + format: 'text' + fail-on-diff: false +``` + +### Check for breaking API changes, and fail if any are found +Copy and paste the following snippet into your build .yml file: +``` +- name: Running OpenAPI Spec diff action + id: test_ete + uses: oasdiff/oasdiff-action/check-breaking@latest + with: + base: https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test1.yaml + revision: https://raw.githubusercontent.com/Tufin/oasdiff/main/data/openapi-test3.yaml + fail-on-diff: true +``` diff --git a/check-breaking/Dockerfile b/check-breaking/Dockerfile new file mode 100644 index 0000000..9d0c98c --- /dev/null +++ b/check-breaking/Dockerfile @@ -0,0 +1,3 @@ +FROM tufin/oasdiff:main +COPY entrypoint.sh /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] \ No newline at end of file diff --git a/check-breaking/action.yml b/check-breaking/action.yml new file mode 100644 index 0000000..bd59c77 --- /dev/null +++ b/check-breaking/action.yml @@ -0,0 +1,20 @@ +name: 'OpenAPI Spec Diff' +description: 'Detect breaking changes in OpenAPI Specification 3' +inputs: + base: + description: 'Path of original OpenAPI spec in YAML or JSON format' + required: true + revision: + description: 'Path of revised OpenAPI spec in YAML or JSON format' + required: true + fail-on-diff: + description: 'Fail with exit code 1 if a difference is found' + required: false + default: false +runs: + using: 'docker' + image: 'Dockerfile' + args: + - ${{ inputs.base }} + - ${{ inputs.revision }} + - ${{ inputs.fail-on-diff }} diff --git a/check-breaking/entrypoint.sh b/check-breaking/entrypoint.sh new file mode 100755 index 0000000..7a04c8a --- /dev/null +++ b/check-breaking/entrypoint.sh @@ -0,0 +1,15 @@ +#!/bin/sh +set -e + +readonly base="$1" +readonly revision="$2" +readonly fail_on_diff="$3" + +echo "running oasdiff check for breaking-changes... base: $base, revision: $revision, fail_on_diff: $fail_on_diff" + +if [ "$fail_on_diff" = "true" ] +then + oasdiff -check-breaking -fail-on-diff -base "$base" -revision "$revision" +else + oasdiff -check-breaking -base "$base" -revision "$revision" +fi diff --git a/diff/Dockerfile b/diff/Dockerfile new file mode 100644 index 0000000..9d0c98c --- /dev/null +++ b/diff/Dockerfile @@ -0,0 +1,3 @@ +FROM tufin/oasdiff:main +COPY entrypoint.sh /entrypoint.sh +ENTRYPOINT ["/entrypoint.sh"] \ No newline at end of file diff --git a/diff/action.yml b/diff/action.yml new file mode 100644 index 0000000..6820117 --- /dev/null +++ b/diff/action.yml @@ -0,0 +1,25 @@ +name: 'OpenAPI Spec Diff' +description: 'A diff tool for OpenAPI Specification 3' +inputs: + base: + description: 'Path of original OpenAPI spec in YAML or JSON format' + required: true + revision: + description: 'Path of revised OpenAPI spec in YAML or JSON format' + required: true + format: + description: 'Output format' + required: false + default: 'yaml' + fail-on-diff: + description: 'Fail with exit code 1 if a difference is found' + required: false + default: false +runs: + using: 'docker' + image: 'Dockerfile' + args: + - ${{ inputs.base }} + - ${{ inputs.revision }} + - ${{ inputs.format }} + - ${{ inputs.fail-on-diff }} diff --git a/diff/entrypoint.sh b/diff/entrypoint.sh new file mode 100755 index 0000000..69da3b2 --- /dev/null +++ b/diff/entrypoint.sh @@ -0,0 +1,16 @@ +#!/bin/sh +set -e + +readonly base="$1" +readonly revision="$2" +readonly format="$3" +readonly fail_on_diff="$4" + +echo "running oasdiff... base: $base, revision: $revision, format: $format, fail_on_diff: $fail_on_diff" + +if [ "$fail_on_diff" = "true" ] +then + oasdiff -fail-on-diff -format "$format" -base "$base" -revision "$revision" +else + oasdiff -format "$format" -base "$base" -revision "$revision" +fi diff --git a/specs/base.yaml b/specs/base.yaml new file mode 100644 index 0000000..acdeb1f --- /dev/null +++ b/specs/base.yaml @@ -0,0 +1,111 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT +servers: + - url: http://petstore.swagger.io/v1 +paths: + /pets: + get: + summary: List all pets + operationId: listPets + tags: + - pets + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: integer + format: int32 + responses: + '200': + description: A paged array of pets + headers: + x-next: + description: A link to the next page of responses + schema: + type: string + content: + application/json: + schema: + $ref: "#/components/schemas/Pets" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + post: + summary: Create a pet + operationId: createPets + tags: + - pets + responses: + '201': + description: Null response + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /pets/{petId}: + get: + summary: Info for a specific pet + operationId: showPetById + tags: + - pets + parameters: + - name: petId + in: path + required: true + description: The id of the pet to retrieve + schema: + type: string + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/Pet" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" +components: + schemas: + Pet: + type: object + required: + - id + - name + properties: + id: + type: integer + format: int64 + name: + type: string + tag: + type: string + Pets: + type: array + items: + $ref: "#/components/schemas/Pet" + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + message: + type: string \ No newline at end of file diff --git a/specs/revision.yaml b/specs/revision.yaml new file mode 100644 index 0000000..fdf6298 --- /dev/null +++ b/specs/revision.yaml @@ -0,0 +1,123 @@ +openapi: "3.0.0" +info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT +servers: + - url: http://petstore.swagger.io/v1 +paths: + /healthcheck: + get: + summary: Health Check + description: >- + The healthcheck endpoint provides detailed information about the health + of a web service. If each of the components required by the service are + healthy, then the service is considered healthy and will return a 200 OK + response. If any of the components needed by the service are unhealthy, + then a 503 Service Unavailable response will be provided. + responses: + '200': + description: Health Check report + /pets: + get: + summary: List all pets + operationId: listPets + tags: + - pets + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: integer + format: int32 + responses: + '200': + description: A paged array of pets + headers: + x-next: + description: A link to the next page of responses + schema: + type: string + content: + application/json: + schema: + $ref: "#/components/schemas/Pets" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + post: + summary: Create a pet + operationId: createPets + tags: + - pets + responses: + '201': + description: Null response + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" + /pets/{petId}: + get: + summary: Info for a specific pet + operationId: showPetById + tags: + - pets + parameters: + - name: petId + in: path + required: true + description: The id of the pet to retrieve + schema: + type: string + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/Pet" + default: + description: unexpected error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" +components: + schemas: + Pet: + type: object + required: + - id + - name + properties: + id: + type: integer + format: int64 + name: + type: string + tag: + type: string + Pets: + type: array + items: + $ref: "#/components/schemas/Pet" + Error: + type: object + required: + - code + - message + properties: + code: + type: integer + format: int32 + message: + type: string \ No newline at end of file